Mar 24, 2026·6 min read·30 visits
Unbounded HTTP Range requests in Rails Active Storage proxy mode cause excessive heap allocations. This leads to Out-of-Memory (OOM) crashes and Denial of Service. Administrators must patch to versions 7.2.3.1, 8.0.4.1, or 8.1.2.1.
Rails Active Storage is vulnerable to a denial of service attack due to improper handling of HTTP Range headers in proxy mode. By supplying an unbounded byte range, an attacker can force the application to perform excessive memory allocation, leading to process termination via the Out-Of-Memory (OOM) killer.
Ruby on Rails Active Storage facilitates file uploads and downloads, integrating cloud storage services securely. The framework includes a proxy mode feature designed to stream files directly through the Rails application rather than redirecting clients to pre-signed cloud provider URLs. This mode relies on the Blobs::ProxyController and the ActiveStorage::Streaming concern to process incoming client requests and transmit file data.
CVE-2026-33174 identifies a severe memory allocation flaw within this proxy streaming implementation. The vulnerability is classified under CWE-789, Memory Allocation with Excessive Size Value. The application fails to enforce upper bounds on the size of byte ranges requested by clients, allowing actors to manipulate the memory footprint of the Rails worker process.
By transmitting a crafted HTTP request containing an unbounded Range header, an attacker forces the application to allocate heap memory proportional to the target file's size. This excessive allocation triggers system-level memory exhaustion, invoking the Out-Of-Memory (OOM) killer to terminate the Rails process. The resulting disruption causes a reliable denial of service condition for the affected application.
The root cause of CVE-2026-33174 stems from the direct translation of user-controlled HTTP header values into memory allocation requests. When a client requests a specific byte range, the ActiveStorage::Streaming module utilizes Rack::Utils.get_byte_ranges to parse the Range header. This utility extracts the requested start and end byte offsets without validating them against application-level memory constraints.
Prior to the patch, the application attempted to read the entire specified byte range from the storage backend into a single contiguous Ruby string buffer. The Ruby interpreter fulfills this by requesting a proportional block of heap memory from the operating system. Because strings in Ruby are mutable and stored contiguously in memory, a request for a multi-gigabyte file segment requires a contiguous memory allocation matching that size.
The OS kernel monitors process memory consumption and intervenes when physical RAM and swap space are exhausted. The kernel's OOM killer heuristically selects processes consuming excessive memory and sends a SIGKILL signal to terminate them. The Rails worker process, having requested the oversized allocation, is immediately terminated, abruptly severing all active connections handled by that worker.
The architectural design of proxy mode necessitates reading data into memory before transmission, differentiating it from redirect mode where the client interacts directly with the storage provider. This fundamental design requirement amplifies the vulnerability, as the application serves as a mandatory intermediary for all data transfer, bearing the full memory cost of the transaction.
The vulnerable code path initiates within the send_blob_byte_range_data method. The original implementation parsed the range header and immediately proceeded to process the data without verifying the total size of the requested chunks.
The patched implementation introduces a mandatory validation step before processing the ranges. The patch adds the ranges_valid? method, which iterates through the requested ranges, calculates the byte difference between the start and end offsets, and sums these values.
# activestorage/app/controllers/concerns/active_storage/streaming.rb
def send_blob_byte_range_data(blob, range_header, disposition: nil)
ranges = Rack::Utils.get_byte_ranges(range_header, blob.byte_size)
return head(:range_not_satisfiable) unless ranges_valid?(ranges)
# Execution continues to stream data...
end
def ranges_valid?(ranges)
return false if ranges.blank? || ranges.all?(&:blank?)
ranges.sum { |range| range.end - range.begin } < ActiveStorage.streaming_chunk_max_size
endThis validation logic rejects requests where the aggregate size exceeds the ActiveStorage.streaming_chunk_max_size configuration variable, defaulting to 100 megabytes. By failing early and returning an HTTP 416 Range Not Satisfiable response, the application prevents the subsequent excessive heap allocation.
Exploitation requires network access to an endpoint serving files via Active Storage in proxy mode. The attacker identifies a target URL associated with a large file, such as a software binary or a high-definition media asset. No authentication is inherently required by the vulnerability, though application-specific access controls on the endpoint must be satisfied.
The attacker issues a standard HTTP GET request to the identified endpoint, appending a malicious Range header. A common payload utilizes an open-ended byte range, such as Range: bytes=0-. This syntax instructs the server to return the entire file starting from byte zero.
Upon receiving the request, the Rails worker process attempts to allocate memory for the entire file payload. For a file exceeding available system memory, this allocation blocks the worker and triggers the system OOM killer. The process is forcefully terminated, terminating the attacker's connection and any concurrent connections handled by the same worker.
The primary impact of CVE-2026-33174 is a localized denial of service affecting the target application's availability. Successful exploitation forcefully terminates the specific Rails worker handling the malicious request. This degrades the overall request processing capacity of the application cluster.
Repeated exploitation by an attacker systematically terminates replacement workers as they are spawned. This sustained attack results in a complete denial of service, rendering the application entirely unresponsive to legitimate user traffic. The CVSS vector reflects this with a High Availability metric (VA:H), while Confidentiality and Integrity remain unaffected (VC:N, VI:N).
In containerized deployment environments, such as Kubernetes or Amazon ECS, the OOM termination often triggers container restarts. Frequent container restarts introduce additional overhead, including application boot times and cache warming delays. This cascading effect exacerbates the initial denial of service, extending the duration of application unavailability.
Administrators must update the activestorage gem to a patched version immediately. The official vulnerability advisory identifies versions 7.2.3.1, 8.0.4.1, and 8.1.2.1 as containing the necessary fixes. Upgrading the gem ensures the new range validation logic is enforced across all proxy streaming endpoints.
Following the upgrade, administrators should evaluate the default ActiveStorage.streaming_chunk_max_size configuration. The 100-megabyte default provides a reasonable baseline, but environments with constrained memory limits require lower thresholds. Modifying config.active_storage.streaming_chunk_max_size = 10.megabytes restricts individual allocations to safer levels for memory-limited hardware.
For systems where immediate patching is unfeasible, administrators can deploy mitigation rules at the Web Application Firewall (WAF) or load balancer level. Rules configured to drop or strip HTTP Range headers on requests directed to /rails/active_storage/blobs/proxy/ paths eliminate the attack vector. While this mitigation breaks legitimate byte-range request functionality, it preserves application availability until the software patch is applied.
A comprehensive defense strategy also incorporates the related fix for CVE-2026-33658, which limits the total number of distinct ranges processed per request. Configuring config.active_storage.streaming_max_ranges = 1 prevents attackers from circumventing chunk size limits by requesting numerous small, adjacent ranges.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U| Product | Affected Versions | Fixed Version |
|---|---|---|
activestorage Ruby on Rails | < 7.2.3.1 | 7.2.3.1 |
activestorage Ruby on Rails | >= 8.0.0.beta1, < 8.0.4.1 | 8.0.4.1 |
activestorage Ruby on Rails | >= 8.1.0.beta1, < 8.1.2.1 | 8.1.2.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-789 |
| Attack Vector | Network |
| CVSS v4.0 Score | 6.6 (Medium) |
| Impact | Denial of Service (Availability) |
| Exploit Status | Proof of Concept |
| CISA KEV | Not Listed |
Memory Allocation with Excessive Size Value
A critical path traversal and authorization bypass vulnerability exists in the rclone serve restic command when multi-user isolation is enabled using the --private-repos flag. Due to a middleware desynchronization flaw, authenticated users can access, modify, or delete backup repositories belonging to other tenants.
A logic vulnerability in the rclone S3 backend implementation allows an unauthenticated adjacent-network attacker to intercept temporary AWS STS credentials. During HTTP redirection handling, the application fails to verify whether a protocol scheme change occurred (such as transitioning from HTTPS to HTTP). If a secure request is redirected to an unencrypted endpoint on the same host, rclone continues to forward the highly sensitive X-Amz-Security-Token header in cleartext.
CVE-2025-15366 is a command injection vulnerability in Python's standard imaplib module, occurring due to the improper neutralization of carriage returns (\r), line feeds (\n), and null bytes (\x00). When an application passes user-controlled input into standard IMAP library calls, an attacker can break out of the line-oriented protocol context and execute arbitrary IMAP directives with the privileges of the authenticated session.
A path traversal vulnerability (Zip Slip variant) exists in rclone's archive extract functionality before version 1.74.4. The command fails to sanitize relative directory components in archive headers, allowing files to be written outside the target directory or cloud prefix. This issue can result in arbitrary file writes or cloud object overwrites depending on the permissions of the credentials used. Nick Craig-Wood authored the patch on June 29, 2026, which was released in version 1.74.4 on July 14, 2026. This vulnerability is assigned CVE-2026-59732 and is cataloged as GHSA-4vr5-p2gc-h23p. This report provides a detailed root cause analysis, code-level diff, and remediation steps.
A local encoding path traversal vulnerability exists in rclone versions from v1.51.0 up to v1.75.0. When non-default local encoding parameters (such as Slash, None, or Raw) are specified, rclone's standard decoder maps safely encoded fullwidth dot-dot characters back into native directory traversal components. Since the local backend historically lacked a post-resolution path containment check, these relative segments resolved outside the designated synchronization root, allowing arbitrary file creation and modification on the host system.
An security bypass vulnerability exists in Nuxt frameworks where route rules containing mixed-case characters are silently dropped during case-insensitive routing. This occurs because lookups are folded to lowercase, but keys are stored in their original casing in the route-matching trie. As a result, critical authorization middleware, such as appMiddleware, is bypassed, allowing unauthorized access to restricted pages.