CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-126081

CVE-2026-126081: Strong Parameters Bypass via Parameters#each_key in Ruby on Rails Action Pack

Amit Schendel
Amit Schendel
Senior Security Researcher

Nov 13, 2026·9 min read·1 visit

Executive Summary (TL;DR)

ActionController::Parameters#each_key returns the internal unpermitted HashWithIndifferentAccess object instead of the Parameters wrapper when called with a block. Passing this return value to Active Model update or creation methods bypasses Strong Parameters checks. Upgrade to Rails 8.1.4.1 or 8.0.5.2 to resolve the issue.

CVE-2026-126081 is a mass-assignment vulnerability (CWE-915) in the Action Pack component of Ruby on Rails. Prior to versions 8.1.4.1 and 8.0.5.2, the ActionController::Parameters#each_key method was delegated directly to the internal ActiveSupport::HashWithIndifferentAccess instance holding raw request parameters. When invoked with a block, #each_key returned the underlying unpermitted hash rather than the ActionController::Parameters wrapper instance. Applications that pass the return value of #each_key directly into Active Model mass-assignment methods bypass Strong Parameters enforcement, allowing attackers to modify restricted model attributes.

Vulnerability Overview

Ruby on Rails utilizes the Action Pack framework (actionpack gem) to handle incoming HTTP requests and route them to controller actions. Within Action Pack, the Strong Parameters feature (ActionController::Parameters) serves as the primary security mechanism protecting Active Record and Active Model objects against mass-assignment vulnerabilities (CWE-915). It requires developers to explicitly declare which incoming request parameters are permitted for mass assignment before passing them into model persistence or initialization methods.

In affected versions of Ruby on Rails (branches 8.0 prior to 8.0.5.2 and 8.1 prior to 8.1.4.1), an implementation flaw in ActionController::Parameters#each_key allows the Strong Parameters verification check to be bypassed. Instead of returning the ActionController::Parameters wrapper instance after iterating over keys with a block, #each_key returns the internal ActiveSupport::HashWithIndifferentAccess object that stores the raw parameters.

Because Active Model only enforces parameter permission checks on objects that respond to the #permitted? method, passing a raw ActiveSupport::HashWithIndifferentAccess instance to methods such as Model.new, Model#update, or Model#assign_attributes skips authorization enforcement entirely. If an application chains #each_key and passes the result to a model operation, an unauthenticated remote attacker can inject arbitrary attributes into the HTTP request to modify sensitive database fields.

This vulnerability is a regression and incomplete remediation of a previously disclosed flaw, CVE-2020-8164. While CVE-2020-8164 corrected identical return-value leaks in #each, #each_pair, and #each_value, the #each_key method remained directly delegated to the internal parameter hash.

Root Cause Analysis

To understand the root cause of CVE-2026-126081, it is necessary to examine the interaction between ActionController::Parameters and ActiveModel::ForbiddenAttributesProtection. When an HTTP request arrives at a Rails controller, the query parameters and request body are parsed into an ActionController::Parameters instance. Internally, this class encapsulates an @parameters instance variable, which is an object of type ActiveSupport::HashWithIndifferentAccess.

When a parameter object is passed to an Active Model mass-assignment method (such as assign_attributes), Active Model invokes sanitize_for_mass_assignment. This internal check inspects whether the incoming argument responds to #permitted?. If the argument responds to #permitted? and the method returns false (the default state for ActionController::Parameters until .permit(...) is called), Rails raises an ActiveModel::ForbiddenAttributesError. However, if the argument does not respond to #permitted?—which is the case for standard Ruby Hash objects and ActiveSupport::HashWithIndifferentAccess—Active Model assumes the hash was constructed internally by the application and permits all attributes within it.

In actionpack/lib/action_controller/metal/strong_parameters.rb, ActionController::Parameters used Active Support's delegate macro to forward several read-only and utility methods directly to the internal @parameters hash:

delegate :keys, :empty?, :exclude?, :include?,
  :as_json, :to_s, :each_key, to: :@parameters

In standard Ruby Hash implementations (and HashWithIndifferentAccess), calling #each_key without a block returns an Enumerator. However, calling #each_key with a block yields each key to the block and then returns self (the receiver of the method call). Because #each_key was delegated to @parameters, the receiver of the method call was @parameters rather than the outer ActionController::Parameters instance. Consequently, params.each_key { |k| ... } returned the unpermitted internal ActiveSupport::HashWithIndifferentAccess directly to the caller, stripping the Strong Parameters protection wrapper.

Code Analysis & Patch Evaluation

The vulnerability was resolved by Mike Dalessio in commits 8ba746e0a786458c281060823f2ccc5c5f6312ac (for the 8.1 branch) and 2fc8838300133931e19eed3ea6cee76a7e83f19c (for the 8.0 branch). The patch modifies actionpack/lib/action_controller/metal/strong_parameters.rb in two primary ways: it removes :each_key from the delegate statement and defines an explicit each_key wrapper method on ActionController::Parameters.

@@ -248,7 +247,7 @@ class Parameters
     # Returns the content of the parameters as a string.
 
     delegate :keys, :empty?, :exclude?, :include?,
-      :as_json, :to_s, :each_key, to: :@parameters
+      :as_json, :to_s, to: :@parameters
 
     alias_method :has_key?, :include?
     alias_method :key?, :include?
@@ -420,6 +419,15 @@ def each_value(&block)
       self
     end
 
+    # Calls block once for each key in the parameters, passing the key. If no block
+    # is given, an enumerator is returned instead.
+    def each_key(&block)
+      return to_enum(:each_key) unless block_given?
+      @parameters.each_key(&block)
+
+      self
+    end
+
     # Returns a new array of the values of the parameters.
     def values
       to_enum(:each_value).to_a

In the patched implementation, ActionController::Parameters#each_key first checks whether a block was provided using block_given?. If no block is present, it returns an Enumerator bound to the Parameters instance via to_enum(:each_key). If a block is provided, it forwards the block to @parameters.each_key(&block) to execute the iteration, but explicitly returns self (the ActionController::Parameters instance) on the final line. This matches the existing secure pattern used by #each_pair and #each_value.

> [!NOTE] > When evaluating the completeness of the fix against the remaining delegated methods (:keys, :empty?, :exclude?, :include?, :as_json, :to_s), none of the boolean, array, or string methods return a hash structure accepted by mass assignment, with the exception of #as_json.

Crucially, the patch authors left :as_json in the delegate list because its explicit contract is to serialize the object into a primitive Ruby Hash representing JSON data. However, to prevent developer misuse, the patch updated the RDoc documentation for #as_json to explicitly warn that it behaves similarly to #to_unsafe_h:

# Like `#to_unsafe_h`, the hash holds every parameter, permitted or not, and
# mass assignment does not check it. Do not pass it to a model.
#
#     params = ActionController::Parameters.new(name: "Bob", admin: true)
#     params.as_json           # => {"name" => "Bob", "admin" => true}
#     User.new(params)         # => ActiveModel::ForbiddenAttributesError
#     User.new(params.as_json) # => #<User name: "Bob", admin: true>

Therefore, while the fix for #each_key is complete and prevents unintended unwrapping during key iteration, security auditors reviewing Rails codebases should remain aware that passing params.as_json to a model constructor remains an unsafe pattern by design.

Exploitation Methodology

Exploiting CVE-2026-126081 requires a specific coding pattern within the target Rails application. Rails does not call #each_key internally during standard request processing or parameter permitting. Exploitation is only possible if application code invokes #each_key with a block on an unpermitted ActionController::Parameters object and passes the return value into an Active Model mass-assignment sink.

This pattern occurs when developers chain parameter validation, logging, audit tracking, or key format verification directly prior to updating or creating a record, mistakenly assuming either that #each_key preserves the Parameters wrapper or that Strong Parameters are enforced elsewhere. Consider the following vulnerable controller implementation:

class UsersController < ApplicationController
  def update
    @user = User.find(params[:id])
 
    # Developer logs incoming attribute keys or validates key formatting
    audited_params = params[:user].each_key do |k|
      Rails.logger.info("User update requested for attribute: #{k}")
    end
 
    # VULNERABLE: audited_params is now an ActiveSupport::HashWithIndifferentAccess.
    # Active Model does not raise ForbiddenAttributesError.
    if @user.update(audited_params)
      render json: @user, status: :ok
    else
      render json: @user.errors, status: :unprocessable_entity
    end
  end
end

To exploit this endpoint, an attacker constructs an HTTP PATCH or PUT request containing additional, unauthorized model attributes alongside normal attributes. For example, if the users database table contains an admin boolean column or a role string column, the attacker submits the following JSON payload:

PATCH /users/42 HTTP/1.1
Host: vulnerable-app.example.com
Content-Type: application/json
 
{
  "user": {
    "name": "standard_user",
    "admin": true,
    "role": "superuser"
  }
}

When the controller executes params[:user].each_key { ... }, the block logs the keys "name", "admin", and "role". The method then returns the underlying HashWithIndifferentAccess containing {"name" => "standard_user", "admin" => true, "role" => "superuser"}. When @user.update(audited_params) executes, Active Model sees a plain hash without a #permitted? method, assigns all three attributes to @user, and commits the changes to the database, granting administrative privileges to the user.

Impact Assessment

The severity of CVE-2026-126081 is rated as High, with a CVSS v3.1 base score of 7.5 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N). The vector reflects that the vulnerability is exploitable over the network (AV:N) with low attack complexity (AC:L), requiring neither privileges (PR:N) nor user interaction (UI:N) when exposed on public-facing endpoints such as user registration or unauthenticated API handlers.

The primary security impact is exclusively focused on Integrity (I:H), with no direct impact to Confidentiality (C:N) or Availability (A:N) in the base CVSS calculation. By bypassing Strong Parameters, an attacker can overwrite any column on the target Active Record model or associated models (if accepts_nested_attributes_for is configured on the model).

In practice, successful exploitation of mass assignment leads to critical secondary impacts depending on the schema of the affected model:

  • Privilege Escalation: Overwriting role flags (admin, is_staff, role_id) or organization ownership (account_id, tenant_id) on user or session models.
  • Business Logic Bypass: Modifying financial or state attributes (e.g., setting balance, paid: true, verified_at, or status: 'approved') on transaction or order models.
  • Account Takeover: Overwriting authentication fields such as email, password_digest, or reset_password_token on user records.

Current threat intelligence indicates an EPSS score of 0.00625 (50.49th percentile), and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. Because exploitation depends on non-standard application code patterns rather than a default framework configuration, automated mass exploitation across arbitrary Rails targets is unlikely.

Remediation & Mitigation

The primary remediation for CVE-2026-126081 is to upgrade Ruby on Rails (rails and actionpack gems) to a patched release. The Rails core team has published fixed versions for the supported 8.0 and 8.1 release branches:

  • For applications running Rails 8.1.x, upgrade to 8.1.4.1 or later.
  • For applications running Rails 8.0.x, upgrade to 8.0.5.2 or later.

Update your application's Gemfile to specify the patched version and run Bundler to update the lockfile:

bundle update rails actionpack

For development and security teams unable to upgrade immediately, or those conducting defense-in-depth code audits, scan the application repository for instances where .each_key or .as_json is called on params objects:

grep -rnE "params(\[[^\]]+\])*\.(each_key|as_json)" app/

If any controller or service object iterates over parameter keys using #each_key, refactor the code so that mass assignment strictly consumes the return value of .require(...).permit(...), rather than the return value of the iteration block:

# Secure Pattern: Explicitly permit parameters before iteration or assignment
def user_params
  params.require(:user).permit(:name, :email)
end
 
def update
  permitted = user_params
  permitted.each_key { |k| Rails.logger.info("Updating key: #{k}") }
  @user.update(permitted)
end

Official Patches

Ruby on RailsGitHub Security Advisory GHSA-wm3x-v3qw-4jh3
Ruby on RailsRails v8.1.4.1 Release Notes
Ruby on RailsRails v8.0.5.2 Release Notes

Fix Analysis (2)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
EPSS Probability
0.63%
Top 50% most exploited

Affected Systems

Ruby on Rails (rails gem)Action Pack (actionpack gem)

Affected Versions Detail

Product
Affected Versions
Fixed Version
actionpack
rails
>= 8.1, < 8.1.4.18.1.4.1
actionpack
rails
< 8.0.5.28.0.5.2
AttributeDetail
CVE IDCVE-2026-126081 (GHSA-wm3x-v3qw-4jh3)
Weakness ClassCWE-915 (Mass Assignment / Improperly Controlled Object Attributes)
CVSS v3.1 Score7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N)
EPSS Score0.63% (50.49th Percentile)
Affected Componentactionpack (ActionController::Parameters#each_key)
Security ImpactStrong Parameters Bypass / Unauthorized Attribute Modification
Exploit StatusNo Known Public Exploits
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1562Impair Defenses
Defense Evasion
T1078Valid Accounts
Privilege Escalation
CWE-915
Improperly Controlled Modification of Dynamically-Determined Object Attributes

The application receives input from an upstream component, but it does not restrict or incorrectly restricts the attributes that can be modified in dynamically-determined objects.

Vulnerability Timeline

Security patches committed to the Ruby on Rails repository by Mike Dalessio.
2026-11-02
Patched Rails versions 8.1.4.1 and 8.0.5.2 tagged and released.
2026-11-03
CVE-2026-126081 and GHSA-wm3x-v3qw-4jh3 officially published.
2026-11-10
NVD, OSV, and EPSS metrics synchronized and updated.
2026-11-12

References & Sources

  • [1]GitHub Security Advisory: GHSA-wm3x-v3qw-4jh3
  • [2]CVE-2026-126081 Official CVE Record
  • [3]NVD Vulnerability Detail: CVE-2026-126081
  • [4]Rails Patch Commit (8.1 branch): 8ba746e0a786458c281060823f2ccc5c5f6312ac
  • [5]Rails Patch Commit (8.0 branch): 2fc8838300133931e19eed3ea6cee76a7e83f19c
  • [6]Ruby on Rails v8.1.4.1 Release
  • [7]Ruby on Rails v8.0.5.2 Release
  • [8]CVE List V5 JSON Record for CVE-2026-126081
Related Vulnerabilities
CVE-2020-8164

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•about 2 hours ago•CVE-2026-126084
4.7

CVE-2026-126084: Unsigned Content-Type in Rails Active Storage GCS Direct Uploads

A vulnerability classified under CWE-345 (Insufficient Verification of Data Authenticity) exists in the Active Storage component of Ruby on Rails prior to versions 8.1.4.1 and 8.0.5.2. When Google Cloud Storage (GCS) is configured as the storage backend with the cache_control option enabled, Active Storage switches from GCS V2 signing to V4 signing for direct upload URLs. Because the V4 signing implementation only binds the Cache-Control and Host headers, the Content-Type and Content-MD5 headers remain unsigned. An attacker can modify the Content-Type header during a direct upload request to store HTML or SVG files with active JavaScript on the GCS bucket origin, enabling Service Worker registration and interception of subsequent signed URL responses within the bucket path.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 3 hours ago•CVE-2026-126079
6.1

CVE-2026-126079: Cross-Site Scripting in Ruby on Rails Action View Text Helpers via HTML5 Serialization Desynchronization

A Cross-Site Scripting (XSS) vulnerability exists in Ruby on Rails Action View prior to versions 8.0.5.2 and 8.1.4.1. When applications use the default HTML5 sanitizer (Rails::HTML5::Sanitizer) with Nokogiri versions prior to 1.19.5, angle brackets (< and >) inside HTML attribute values are serialized unescaped. Action View text helpers—specifically highlight and simple_format—perform string-based manipulations on the sanitized HTML rather than operating on the DOM tree. An unescaped '>' character or a double newline ('\n\n') inside an attribute value causes these helpers to misidentify tag or paragraph boundaries, breaking out of the attribute context and emitting inert attribute contents as live HTML elements in the final html_safe output.

Amit Schendel
Amit Schendel
2 views•10 min read
•about 4 hours ago•CVE-2026-126070
6.1

CVE-2026-126070: Cross-Site Scripting in Ruby on Rails Action View strip_tags Helper

CVE-2026-126070 is a Cross-Site Scripting (XSS) vulnerability in the Action View component of Ruby on Rails. Prior to versions 8.0.5.2 and 8.1.4.1, the strip_tags helper returned sanitized output marked as html_safe without encoding single or double quotation marks. When applications render the output of strip_tags inside quoted HTML attributes in ERB templates, attackers can break out of the attribute context and inject arbitrary HTML attributes or JavaScript event handlers.

Amit Schendel
Amit Schendel
3 views•10 min read
•about 5 hours ago•CVE-2026-126078
6.1

CVE-2026-126078: Cross-Site Scripting in Ruby on Rails Action View highlight Helper

CVE-2026-126078 is a Cross-Site Scripting (XSS) vulnerability classified under CWE-79 affecting the Action View component of Ruby on Rails in versions prior to 8.0.5.2 and 8.1.4.1. The vulnerability resides in the ActionView::Helpers::TextHelper#highlight method when invoked with a custom :highlighter template that places capture group placeholders inside HTML attribute values. Because matched substrings are substituted without HTML escaping after initial sanitization preserves literal quotation marks, an attacker controlling the input text or target search phrase can break out of the surrounding attribute delimiter and inject arbitrary HTML attributes or JavaScript event handlers.

Amit Schendel
Amit Schendel
3 views•9 min read
•about 6 hours ago•CVE-2026-126077
6.8

CVE-2026-126077: Session Information Leak in Ruby on Rails Action Pack and Active Storage Proxy Mode

An information exposure vulnerability in Ruby on Rails Action Pack allows sensitive session cookies to be attached to public, cacheable responses served by Active Storage proxy controllers. When cookie secret rotation or a hybrid cookie serializer migration is enabled, reading a legacy-format cookie triggers an automatic cookie rewrite that ignores the session-skipping directive. If an intermediate shared cache or CDN caches the resulting response along with its Set-Cookie header, subsequent users requesting the same URL receive the leaked session token.

Amit Schendel
Amit Schendel
4 views•11 min read
•about 7 hours ago•CVE-2026-126072
5.9

CVE-2026-126072: Thread Deadlock and Denial of Service in Ruby on Rails ActionController::Live

CVE-2026-126072 (GHSA-rwvh-fw6r-pwvp) is a concurrency deadlock vulnerability in the Ruby on Rails Action Pack framework affecting applications that utilize ActionController::Live response streaming. The defect occurs due to improper synchronization within ActionController::Live::Buffer when handling full bounded queues during stream closure and connection abortion. An unauthenticated remote attacker can trigger this condition by stalling TCP socket reads on streaming endpoints—including Active Storage proxy mode—resulting in permanent worker thread exhaustion and application-wide denial of service.

Amit Schendel
Amit Schendel
4 views•10 min read