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-33173

CVE-2026-33173: Content Type Bypass via Metadata Injection in Rails Active Storage

Amit Schendel
Amit Schendel
Senior Security Researcher

Mar 24, 2026·7 min read·84 visits

Executive Summary (TL;DR)

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.

Vulnerability Overview

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.

Root Cause Analysis

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.

Code Analysis

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
end

The 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.

Exploitation Mechanics

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).

System Interaction Diagram

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.

Impact Assessment

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.

Remediation and Mitigation Guidance

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.

Official Patches

Ruby on RailsOfficial GitHub Security Advisory
Ruby on RailsRelease Tag 7.2.3.1
Ruby on RailsRelease Tag 8.0.4.1
Ruby on RailsRelease Tag 8.1.2.1

Fix Analysis (3)

Technical Appendix

CVSS Score
5.3/ 10
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

Affected Systems

Ruby on RailsActive Storage

Affected Versions Detail

Product
Affected Versions
Fixed Version
Rails Active Storage
Ruby on Rails
< 7.2.3.17.2.3.1
Rails Active Storage
Ruby on Rails
>= 8.0.0.beta1, < 8.0.4.18.0.4.1
Rails Active Storage
Ruby on Rails
>= 8.1.0.beta1, < 8.1.2.18.1.2.1
AttributeDetail
CWE IDCWE-915
Attack VectorNetwork
CVSS v4.05.3
ImpactContent Type Bypass / Stored XSS
Exploit StatusNone
CISA KEVFalse

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.007Command and Scripting Interpreter: JavaScript
Execution
CWE-915
Improperly Controlled Modification of Dynamically-Determined Object Attributes

Improperly Controlled Modification of Dynamically-Determined Object Attributes

Vulnerability Timeline

Initial fix commits authored
2026-01-07
Vulnerability disclosed and GHSA-qcfx-2mfw-w4cg published
2026-03-23
CVE-2026-33173 published by NVD
2026-03-23
Patched Rails versions 7.2.3.1, 8.0.4.1, and 8.1.2.1 released
2026-03-23

References & Sources

  • [1]GitHub Security Advisory GHSA-qcfx-2mfw-w4cg
  • [2]Fix Commit (8.1.x)
  • [3]Fix Commit (8.0.x)
  • [4]Fix Commit (7.2.x)

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

•1 day ago•CVE-2026-58197
8.8

CVE-2026-58197: Host Escape and Lateral Movement via Insecure Container Network Defaults in ToolHive

A high-severity access control vulnerability in ToolHive CLI before v0.30.1 and ToolHive Studio before v0.38.0 allows local containerized MCP servers to bypass network isolation. This enables malicious workloads to establish TCP/IP connections to administrative and control plane endpoints exposed on the host loopback interface.

Amit Schendel
Amit Schendel
8 views•8 min read
•1 day ago•CVE-2026-63405
5.9

CVE-2026-63405: Insufficient Verification of Data Authenticity in AnyCable Pusher REST API

AnyCable is a real-time communication server. Prior to version 1.6.15, its Pusher-compatible REST API suffered from an authentication bypass vulnerability because it failed to verify that the request body matched the signature-validated body_md5 parameter. This allows attackers to perform replay attacks with modified body contents.

Amit Schendel
Amit Schendel
9 views•5 min read
•1 day ago•CVE-2026-64847
6.8

CVE-2026-64847: Indefinite Denial of Service via Undrained Stderr in AnyIO Process Pool Workers

A denial-of-service vulnerability exists in AnyIO prior to version 4.14.2. Standard error streams of process-pool workers are connected to an operating system pipe that is never drained by the parent process. This allows a worker to fill the pipe buffer and deadlock indefinitely.

Amit Schendel
Amit Schendel
8 views•6 min read
•2 days ago•CVE-2026-63349
7.0

CVE-2026-63349: Privilege Dropping Bypass and Denial of Service in AnyIO Subprocess Module

CVE-2026-63349 is a critical privilege-dropping bypass vulnerability in the AnyIO asynchronous framework (versions 4.14.0 and 4.14.1) on POSIX platforms. Due to a variable assignment typo, supplementary groups specified by the developer are not correctly propagated to the execution backend, resulting in subprocesses retaining the parent process's elevated supplementary group permissions.

Alon Barad
Alon Barad
14 views•5 min read
•2 days ago•CVE-2026-63406
5.9

CVE-2026-63406: Information Disclosure via Insecure Telemetry and Hardcoded Credentials in AnyCable-Go

CVE-2026-63406 is an information disclosure vulnerability in AnyCable-go prior to version 1.6.15. The built-in telemetry client is enabled by default with a hardcoded public authentication token ('secret'). This client digests highly sensitive configuration parameters and command-line arguments, including JWT secrets and RPC secrets, into a stable SHA-256 fingerprint. This fingerprint is sent over public networks, exposing those administrative secrets to offline dictionary and brute-force attacks if intercepted.

Alon Barad
Alon Barad
7 views•5 min read
•2 days ago•CVE-2026-84992
6.1

CVE-2026-84992: Cross-Site Scripting (XSS) via Fenced Code Block Parsing in md-editor-v3

CVE-2026-84992 is a Cross-Site Scripting (XSS) vulnerability affecting md-editor-v3 before version 6.5.4. It occurs because the fenced-code block language parser directly interpolates unescaped language metadata into unquoted HTML attributes inside the custom rendering callback. This bypasses the built-in XSSPlugin which runs during the parsing phase, before rendering.

Amit Schendel
Amit Schendel
9 views•6 min read