{"id":"GHSA-wm3x-v3qw-4jh3","kind":"vulnerability","aliases":["GHSA-wm3x-v3qw-4jh3"],"related":[],"title":"Possible Strong Parameters bypass in Parameters#each_key in Action Pack","description":"### Impact\n`ActionController::Parameters#each_key` delegates to the internal `ActiveSupport::HashWithIndifferentAccess` that holds the request parameters, so when called with a block it returns that hash instead of the `Parameters` instance. The hash does not respond to `permitted?`, so Active Model mass assignment (`new`, `assign_attributes`, `update`) accepts it without raising `ActiveModel::ForbiddenAttributesError`. An application that passes the return value of `each_key` to mass assignment could allow a remote, unauthenticated attacker to set attributes that the application does not permit, such as an authorization flag.\n\nThis is an incomplete fix of [CVE-2020-8164](https://github.com/advisories/GHSA-8727-m6gj-mc37), which made `each`, `each_pair` and `each_value` return the `Parameters` instance but left `each_key` delegated.\n\n### Details\nThe fixed releases define `Parameters#each_key` to yield each key and return the `Parameters` instance when given a block, as `each`, `each_pair` and `each_value` do, and to return an `Enumerator` without one. Code that used the return value of `each_key` as a hash now receives the `Parameters` instance, which mass assignment rejects unless it is permitted.\n\n### Affected applications\nAn application is affected if it passes the return value of `ActionController::Parameters#each_key`, called with a block, to mass assignment. Rails itself makes no such call.\n\n### Workarounds\nDo not use the return value of `each_key`. Call it for its block only, and pass the permitted `Parameters` instance to mass assignment.\n\n### Releases\nThe fixed releases are available at the normal locations.\n\nPatches for those who cannot upgrade at once:\n- 8.1: https://github.com/rails/rails/commit/8ba746e0a786458c281060823f2ccc5c5f6312ac.patch\n- 8.0: https://github.com/rails/rails/commit/2fc8838300133931e19eed3ea6cee76a7e83f19c.patch\n\n### Versions affected\n- actionpack < 8.0.5.2\n- actionpack >= 8.1, < 8.1.4.1\n\n### Credit\nThis issue was responsibly reported by HackerOne researcher [smlee](https://hackerone.com/smlee).","summary":"Action Pack's ActionController::Parameters#each_key returns an internal hash instead of the Parameters object when called with a block. Mass assignment then accepts that hash without the permitted check, so an attacker can set attributes the application does not allow, such as an authorization flag.","severity":"high","cvss":7.5,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"actionpack","fixed":["8.1.4.1"],"affected":">= 8.1, < 8.1.4.1","ecosystem":"rubygems"},{"name":"actionpack","fixed":["8.0.5.2"],"affected":"< 8.0.5.2","ecosystem":"rubygems"}],"ecosystems":["rubygems"],"tags":["actionpack","cwe-915","package","rails","ruby","web-app"],"not_affected_if":["no-each-key-in-mass-assignment","not-rails"],"how_to_check":"- Run `bundle exec ruby -e \"require 'action_pack'; puts ActionPack::VERSION::STRING\"` or check Gemfile.lock for `actionpack` below `8.0.5.2` or in `8.1.x` below `8.1.4.1`\n- Search the application code for `each_key` calls whose return value is passed to `new`, `assign_attributes` or `update`","fix":"- actionpack `8.1.4.1` for the 8.1 line\n- actionpack `8.0.5.2` for the 8.0 line\n- Patch commits for those who cannot upgrade yet are linked in the advisory (8.1 and 8.0 commits)","status":"open","published_at":"2026-11-04T03:02:14+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","triaged_at":"2026-11-09T22:54:19+00:00","updated_at":"2026-11-09T22:54:19+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:54:19Z","model":"claude-haiku-5-5","output":{"fix":"- actionpack `8.1.4.1` for the 8.1 line\n- actionpack `8.0.5.2` for the 8.0 line\n- Patch commits for those who cannot upgrade yet are linked in the advisory (8.1 and 8.0 commits)","reach":"internet","title":"Rails Action Pack: each_key return value can bypass strong parameters","impact":"medium","summary":"Action Pack's ActionController::Parameters#each_key returns an internal hash instead of the Parameters object when called with a block. Mass assignment then accepts that hash without the permitted check, so an attacker can set attributes the application does not allow, such as an authorization flag.","audience":"businesses","category":"package","nicknames":[],"who_cares":["rails","actionpack","ruby","web-app"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"Attacker sets unpermitted attributes, such as an authorization flag, on records","analyst_note":"","how_to_check":"- Run `bundle exec ruby -e \"require 'action_pack'; puts ActionPack::VERSION::STRING\"` or check Gemfile.lock for `actionpack` below `8.0.5.2` or in `8.1.x` below `8.1.4.1`\n- Search the application code for `each_key` calls whose return value is passed to `new`, `assign_attributes` or `update`","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["no-each-key-in-mass-assignment","not-rails"],"who_is_affected":"Only Rails applications that pass the return value of Parameters#each_key, called with a block, into mass assignment are exposed. The advisory states Rails itself makes no such call, so applications that do not use that pattern are not affected by this path.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"high"},"cost_usd":0.000855,"input_tokens":5330,"output_tokens":644,"severity_before":"high"},"analyst_status":null,"analyst_note":null,"search":"'-2020':173C '-8164':174C '-915':26B '/advisories/ghsa-8727-m6gj-mc37),':177C '/rails/rails/commit/2fc8838300133931e19eed3ea6cee76a7e83f19c.patch':336C '/rails/rails/commit/8ba746e0a786458c281060823f2ccc5c5f6312ac.patch':332C '/smlee).':356C '4jh3':16A,21A '8.0':333C '8.0.5.2':340C '8.1':329C,342C '8.1.4.1':343C 'accept':57B,127C 'action':10A,33B 'actioncontrol':36B,81C,269C 'actionpack':22A,23A,24B,339C,341C 'activ':119C 'activemodel':131C 'activesupport':89C 'affect':256C,261C,338C 'allow':74B,147C 'app':32B 'applic':71B,134C,157C,257C,259C 'assign':55B,122C,124C,145C,250C,279C,310C 'attack':66B,151C 'attribut':69B,125C,154C 'author':78B,164C 'avail':316C 'block':53B,101C,215C,276C,300C 'bypass':4A 'call':50B,98C,273C,285C,296C 'cannot':325C 'check':63B 'code':231C 'could':146C 'credit':344C 'cve':172C 'cwe':25B 'defin':199C 'deleg':85C,194C 'detail':195C 'enumer':228C 'fix':170C,197C,313C 'flag':79B,165C 'forbiddenattributeserror':132C 'ghsa':13A,18A 'ghsa-wm3x-v3qw-4jh3':12A,17A 'github.com':176C,331C,335C 'github.com/advisories/ghsa-8727-m6gj-mc37),':175C 'github.com/rails/rails/commit/2fc8838300133931e19eed3ea6cee76a7e83f19c.patch':334C 'github.com/rails/rails/commit/8ba746e0a786458c281060823f2ccc5c5f6312ac.patch':330C 'given':213C 'hackeron':351C 'hackerone.com':355C 'hackerone.com/smlee).':354C 'hash':43B,59B,105C,112C,242C 'hashwithindifferentaccess':90C 'hold':92C 'impact':80C 'incomplet':169C 'instanc':110C,189C,211C,247C,307C 'instead':44B,106C 'intern':42B,88C 'issu':346C 'key':8A,39B,84C,142C,193C,202C,206C,239C,272C,295C 'left':191C 'locat':320C 'made':179C 'make':282C 'mass':54B,121C,144C,249C,278C,309C 'model':120C 'new':123C 'normal':319C 'object':48B 'one':230C 'pack':11A,34B 'packag':27B 'pair':182C,219C 'paramet':3A,6A,37B,47B,82C,95C,109C,188C,200C,210C,246C,270C,306C 'pass':136C,264C,303C 'patch':321C 'permit':62B,117C,160C,255C,305C 'possibl':1A 'rail':28B,280C 'rais':130C 'receiv':244C 'reject':251C 'releas':198C,311C,314C 'remot':149C 'report':349C 'request':94C 'research':352C 'respond':115C 'respons':348C 'return':40B,103C,138C,186C,208C,226C,235C,266C,291C 'rubi':29B 'set':68B,153C 'smlee':353C 'strong':2A 'unauthent':150C 'unless':252C 'updat':126C 'upgrad':326C 'use':233C,289C 'v3qw':15A,20A 'valu':139C,185C,222C,236C,267C,292C 'version':337C 'web':31B 'web-app':30B 'without':60B,129C,229C 'wm3x':14A,19A 'workaround':286C 'yield':204C","nicknames":[],"mitigations":[],"who_affected":"Only Rails applications that pass the return value of Parameters#each_key, called with a block, into mass assignment are exposed. The advisory states Rails itself makes no such call, so applications that do not use that pattern are not affected by this path.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["actionpack"],"ptokens":["actionpack"],"labels":["actionpack","cwe915","high","package","rails","ruby","rubygems","webapp"],"campaign_type":null,"search_a":"'4jh3':16A,21A 'action':10A 'actionpack':22A,23A 'bypass':4A 'ghsa':13A,18A 'ghsa-wm3x-v3qw-4jh3':12A,17A 'key':8A 'pack':11A 'paramet':3A,6A 'possibl':1A 'strong':2A 'v3qw':15A,20A 'wm3x':14A,19A","search_b":"'-915':26B 'accept':57B 'action':33B 'actioncontrol':36B 'actionpack':24B 'allow':74B 'app':32B 'applic':71B 'assign':55B 'attack':66B 'attribut':69B 'author':78B 'block':53B 'call':50B 'check':63B 'cwe':25B 'flag':79B 'hash':43B,59B 'instead':44B 'intern':42B 'key':39B 'mass':54B 'object':48B 'pack':34B 'packag':27B 'paramet':37B,47B 'permit':62B 'rail':28B 'return':40B 'rubi':29B 'set':68B 'web':31B 'web-app':30B 'without':60B","search_c":"'-2020':173C '-8164':174C '/advisories/ghsa-8727-m6gj-mc37),':177C '/rails/rails/commit/2fc8838300133931e19eed3ea6cee76a7e83f19c.patch':336C '/rails/rails/commit/8ba746e0a786458c281060823f2ccc5c5f6312ac.patch':332C '/smlee).':356C '8.0':333C '8.0.5.2':340C '8.1':329C,342C '8.1.4.1':343C 'accept':127C 'actioncontrol':81C,269C 'actionpack':339C,341C 'activ':119C 'activemodel':131C 'activesupport':89C 'affect':256C,261C,338C 'allow':147C 'applic':134C,157C,257C,259C 'assign':122C,124C,145C,250C,279C,310C 'attack':151C 'attribut':125C,154C 'author':164C 'avail':316C 'block':101C,215C,276C,300C 'call':98C,273C,285C,296C 'cannot':325C 'code':231C 'could':146C 'credit':344C 'cve':172C 'defin':199C 'deleg':85C,194C 'detail':195C 'enumer':228C 'fix':170C,197C,313C 'flag':165C 'forbiddenattributeserror':132C 'github.com':176C,331C,335C 'github.com/advisories/ghsa-8727-m6gj-mc37),':175C 'github.com/rails/rails/commit/2fc8838300133931e19eed3ea6cee76a7e83f19c.patch':334C 'github.com/rails/rails/commit/8ba746e0a786458c281060823f2ccc5c5f6312ac.patch':330C 'given':213C 'hackeron':351C 'hackerone.com':355C 'hackerone.com/smlee).':354C 'hash':105C,112C,242C 'hashwithindifferentaccess':90C 'hold':92C 'impact':80C 'incomplet':169C 'instanc':110C,189C,211C,247C,307C 'instead':106C 'intern':88C 'issu':346C 'key':84C,142C,193C,202C,206C,239C,272C,295C 'left':191C 'locat':320C 'made':179C 'make':282C 'mass':121C,144C,249C,278C,309C 'model':120C 'new':123C 'normal':319C 'one':230C 'pair':182C,219C 'paramet':82C,95C,109C,188C,200C,210C,246C,270C,306C 'pass':136C,264C,303C 'patch':321C 'permit':117C,160C,255C,305C 'rail':280C 'rais':130C 'receiv':244C 'reject':251C 'releas':198C,311C,314C 'remot':149C 'report':349C 'request':94C 'research':352C 'respond':115C 'respons':348C 'return':103C,138C,186C,208C,226C,235C,266C,291C 'set':153C 'smlee':353C 'unauthent':150C 'unless':252C 'updat':126C 'upgrad':326C 'use':233C,289C 'valu':139C,185C,222C,236C,267C,292C 'version':337C 'without':129C,229C 'workaround':286C 'yield':204C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-04T03:02:14+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-wm3x-v3qw-4jh3","url":"https://github.com/rails/rails/security/advisories/GHSA-wm3x-v3qw-4jh3","severity":"high","published_at":"2026-11-04T03:02:14+00:00","modified_at":"2026-11-04T03:02:14+00:00","first_seen_at":"2026-11-09T22:53:29+00:00","fetched_at":"2026-11-09T22:53:29+00:00","note":null}],"documents":[{"id":110666,"url":"https://github.com/rails/rails/security/advisories/GHSA-wm3x-v3qw-4jh3","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}