Mar 24, 2026·7 min read·36 visits
A parameter injection flaw in Rails Active Storage allows attackers to bypass file type validation by setting internal metadata flags (e.g., 'identified: true') during direct uploads. This enables the uploading of dangerous file types, leading to potential Stored Cross-Site Scripting (XSS).
Ruby on Rails Active Storage versions prior to 7.2.3.1, 8.0.4.1, and 8.1.2.1 contain an insecure parameter handling vulnerability in the DirectUploadsController. Attackers can inject internal state flags into the metadata JSON column during file upload initialization, bypassing server-side content type verification and enabling the upload of malicious payloads such as HTML files masquerading as benign images.
Active Storage is a core framework in Ruby on Rails responsible for attaching cloud and local files to application records. The DirectUploadsController manages the initialization phase of client-direct uploads, allowing browsers to upload files directly to backend storage services like Amazon S3 or Google Cloud Storage. During this initialization, the client provides metadata about the file, including its filename, byte size, checksum, and content type.
The vulnerability exists within the handling of the metadata parameter during the creation of an ActiveStorage::Blob record. The metadata field is a JSON-serialized column in the database used to store both user-supplied context and internal framework state. Because the framework does not sanitize the incoming metadata hash, external clients can specify internal state flags that Active Storage relies on for security and processing logic.
By manipulating these state flags, an attacker can coerce the framework into trusting a spoofed MIME type. This allows the upload of arbitrary content that bypasses application-level file type restrictions. The flaw is classified under CWE-915 (Improperly Controlled Modification of Dynamically-Determined Object Attributes) and affects multiple release lines of Ruby on Rails.
The root cause of CVE-2026-33173 is the insecure merging of untrusted client input into a structured data column used for internal state management. Active Storage tracks the processing status of a blob using specific boolean flags within the metadata hash. The most critical of these flags is identified, which indicates whether the system has definitively verified the file's MIME type via magic byte inspection.
When a client initiates a direct upload via the DirectUploadsController#create action, the controller extracts the metadata dictionary from the request payload. This dictionary is passed directly to the ActiveStorage::Blob.create_before_direct_upload! method without any filtering or sanitization. The framework blindly persists the user-supplied hash into the active_storage_blobs table.
If the incoming payload contains "identified": true, Active Storage processes subsequent interactions with the blob under the assumption that the content_type attribute has already been securely validated. The framework skips the standard MIME type detection routines. Consequently, the declared content_type is trusted unconditionally, severing the link between the actual file content and the application's verification mechanisms.
The vulnerable code path allowed arbitrary key-value pairs to enter the database. Prior to the patch, the create_before_direct_upload! method accepted the metadata argument and passed it directly to the creation routine. Any keys provided by the client were retained.
The official patch mitigates this by implementing an explicit blocklist for protected internal keys. The Rails maintainers introduced a PROTECTED_METADATA constant containing the specific flags utilized by Active Storage state machines.
# activestorage/app/models/active_storage/blob.rb
PROTECTED_METADATA = %w(analyzed identified composed)
def create_before_direct_upload!(filename:, byte_size:, checksum:, content_type: nil, metadata: nil, custom_metadata: nil)
metadata = filter_metadata(metadata)
create!(
filename: filename,
byte_size: byte_size,
checksum: checksum,
content_type: content_type,
metadata: metadata,
custom_metadata: custom_metadata
)
end
private
def filter_metadata(metadata)
if metadata.is_a?(Hash)
metadata.without(*PROTECTED_METADATA)
else
metadata
end
endThe filter_metadata private method ensures that the analyzed, identified, and composed keys are stripped from the hash before persistence. While this blocklist approach effectively resolves the immediate vulnerability, developers must ensure no future internal state keys are added to the metadata hash without also updating the PROTECTED_METADATA constant.
Exploiting this vulnerability requires the attacker to have authorization to initiate direct uploads within the target application. The attacker intercepts or scripts the initial POST request to the /rails/active_storage/direct_uploads endpoint. They modify the JSON payload to include the protected metadata flags while specifying a malicious file payload and a benign content type.
The following JSON structure demonstrates the payload required to trigger the vulnerability. The attacker sets the content_type to image/png to bypass application-level validation filters, while the actual file contents uploaded to the storage provider contain an HTML payload with embedded JavaScript.
{
"blob": {
"filename": "profile_picture.html",
"byte_size": 2048,
"checksum": "[VALID_CHECKSUM]",
"content_type": "image/png",
"metadata": {
"identified": true,
"analyzed": true,
"composed": true
}
}
}Upon receiving this request, the server persists the blob record with the spoofed metadata and returns a signed direct upload URL. The attacker uploads the malicious HTML file to the provided storage URL. When the application subsequently serves this file to users, the content_type is rendered as image/png, or the file bypasses image-only restrictions. Depending on the storage configuration and content-disposition headers, a browser accessing the raw file URL may execute the HTML payload, resulting in Stored Cross-Site Scripting (XSS).
The following diagram illustrates the vulnerable direct upload flow and how the injected metadata persists through the Active Storage architecture.
This execution path demonstrates the critical failure in input validation at the boundary of the DirectUploadsController and the ActiveStorage::Blob model.
The vulnerability allows unauthenticated or authenticated users (depending on the application's upload requirements) to bypass critical file type restrictions. The assigned CVSS v4.0 vector is CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N, resulting in a Base Score of 5.3 (Medium). The impact is primarily localized to the integrity of the data processing pipeline.
The concrete security consequence is the ability to store files with mismatched MIME types and internal state flags. The primary attack vector is Stored Cross-Site Scripting (XSS). If the targeted application serves uploaded files directly from its domain without forcing a Content-Disposition: attachment header, browsers may sniff the file contents or render malicious HTML/JavaScript payloads.
Secondary impacts include the disruption of backend processing jobs. By artificially setting the analyzed flag, attackers can prevent Active Storage from generating variants (such as image thumbnails) or extracting required metadata (such as image dimensions). This can lead to application errors or layout breakage when the application attempts to render unanalyzed blobs.
The definitive remediation for CVE-2026-33173 is upgrading to the patched versions of the Ruby on Rails framework. Administrators must update their Gemfile to use Active Storage version 7.2.3.1, 8.0.4.1, or 8.1.2.1. Following the version bump, a full test suite run is required to ensure compatibility with the updated filtering logic.
If immediate patching is not technically feasible, developers can mitigate the flaw by implementing a custom before_action in the DirectUploadsController. This filter should inspect the incoming params[:blob][:metadata] parameter and forcefully remove the keys analyzed, identified, and composed before the parameter reaches the Active Storage models.
As a defense-in-depth measure, applications should enforce strict Content-Security-Policy (CSP) headers on all domains serving user-uploaded content. Additionally, configuring cloud storage buckets to serve all user uploads with the Content-Disposition: attachment header will prevent browsers from rendering malicious payloads inline, neutralizing the XSS risk regardless of the underlying metadata state.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
Rails Active Storage Ruby on Rails | < 7.2.3.1 | 7.2.3.1 |
Rails Active Storage Ruby on Rails | >= 8.0.0.beta1, < 8.0.4.1 | 8.0.4.1 |
Rails Active Storage Ruby on Rails | >= 8.1.0.beta1, < 8.1.2.1 | 8.1.2.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-915 |
| Attack Vector | Network |
| CVSS v4.0 | 5.3 |
| Impact | Content Type Bypass / Stored XSS |
| Exploit Status | None |
| CISA KEV | False |
Improperly Controlled Modification of Dynamically-Determined Object Attributes
CVE-2026-48861 is a client-side HTTP request-line CRLF (Carriage Return Line Feed) injection vulnerability in the popular Elixir HTTP client library, Mint. The vulnerability permits HTTP Request Splitting and HTTP Request Smuggling when an application forwards untrusted, attacker-controlled inputs to Mint's HTTP client requests as either the HTTP request method or target. By embedding CRLF characters within these parameters, an attacker can terminate the request line prematurely, inject malicious headers, or pipeline entirely independent requests. These smuggled requests are then processed by upstream or downstream proxy servers as separate HTTP queries on the same TCP connection. While Mint version 1.7.0 introduced target validation to secure the request target, the HTTP request method parameter remained completely unvalidated. This flaw allows attackers to bypass routing filters, access restricted internal APIs, or poison HTTP caches under default configurations.
An Inconsistent Interpretation of HTTP Requests (HTTP Request/Response Smuggling) vulnerability in the Elixir Mint HTTP client allows attacker-controlled HTTP/1 servers to desynchronize response framing on shared connections due to over-lenient parsing of sign-prefixed Content-Length headers.
An allocation of resources without limits or throttling vulnerability in Elixir Mint allows an attacker-controlled HTTP/2 server to exhaust memory in a Mint client. The vulnerability is exploited by sending a HEADERS frame without the END_HEADERS flag followed by an infinite stream of CONTINUATION frames. Because the client lacks limits on the incoming header-block accumulator, the client continuously consumes memory until an out-of-memory crash occurs.
CVE-2026-48596 is an Improper Neutralization of CRLF Sequences in HTTP Headers (HTTP Request/Response Splitting, CWE-113) in the Elixir Tesla HTTP client. The flaw resides in how multipart content-type parameters are joined and serialized, enabling attackers to inject arbitrary headers or split HTTP requests when applications pass untrusted inputs to the parameters of multipart uploads.
An improper handling of highly compressed data (decompression bomb) vulnerability exists in the Elixir Tesla HTTP client when utilizing response decompression middlewares. By serving highly compressed responses or stacked content-encoding headers, a malicious server can cause arbitrary heap exhaustion, leading to a denial of service (DoS) crash in the BEAM virtual machine.
A high-severity security vulnerability in Elixir's Tesla HTTP client library (CVE-2026-48595) allows unauthenticated remote attackers to harvest sensitive credentials, including Authorization headers and cookies. The flaw resides in the 'Tesla.Middleware.FollowRedirects' component, which performs case-sensitive lookups when stripping credentials during cross-origin redirects. Because HTTP headers are case-insensitive by RFC specifications, standard canonical casing (e.g., 'Authorization') bypasses the lowercase-only blocklist, leaking tokens to untrusted external redirect destinations.