CVE-2025-61772
High · 7.5Rack's multipart parser buffers unbounded per-part headers, enabling DoS (memory exhaustion)
CVSS
7.5
EPSS
0.9%
Published
Oct 7, 2025
CISA due date
—
Cloudanix analysis
A malformed upload request can make affected Ruby web applications run out of memory and become unavailable.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- Low
- Impact
- Denial Of Service
- Component
- Library
- Class
- Denial of service
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
Rack::Multipart::Parser mishandles malformed multipart/form-data requests when a multipart part begins a header block that never terminates with the required blank line sequence. Instead of enforcing a bounded header-size limit or rejecting the malformed part promptly, the parser can continue appending incoming bytes to an in-memory buffer. A remote unauthenticated client that can reach an endpoint using Rack multipart parsing can therefore cause process memory growth, garbage-collection pressure, worker crashes, or host/container out-of-memory termination. The impact is denial of service rather than code execution or data disclosure.
Why it matters to the business
Public or internal Ruby applications that accept file uploads or multipart form submissions through affected Rack code may be made slow or unavailable by relatively simple malformed HTTP requests. This can interrupt customer-facing services, APIs, administrative portals, CI/CD callbacks, or any application workflow that relies on multipart request handling. The vulnerability is not in CISA KEV, has no known mature public exploitation in the provided data, and has a low EPSS score of 0.00868, but it has been public for 306 days, so internet-exposed upload endpoints should still be treated as practical denial-of-service risk.
How an attack unfolds
An attacker first identifies a Rack-backed application endpoint that accepts multipart/form-data, commonly an upload or form submission route. The attacker then opens one or more HTTP requests declaring a multipart body and sends a part whose header section is intentionally malformed so the expected header terminator is never reached. As the request body continues, Rack::Multipart::Parser keeps accumulating bytes in memory while waiting for the missing terminator. Repeating this across concurrent connections or with sufficiently large bodies can consume application worker memory, trigger Ruby NoMemoryError conditions, cause container or process OOM kills, or make the service unresponsive until workers restart or traffic is blocked.
How to fix it
Update Rack to a fixed revision or release containing the upstream fix. For deployments tracking rack/rack from Git, ensure the code includes commit 4c4ea296fdfd115377912aa7dbcb55b83bf2888e or a later commit/release that incorporates it. Rebuild and redeploy applications that vendor Rack or bundle it through dependency lockfiles, and verify that transitive dependencies do not pin an affected Rack version. As compensating controls, enforce request body size limits, multipart header/field limits, upload size limits, request timeouts, and connection rate limits at the reverse proxy, load balancer, WAF, or application server. Disable or restrict multipart upload endpoints that are not required, and ensure process supervisors/container orchestrators have sane memory limits and restart policies to reduce outage duration.
How to confirm the fix worked
Confirm the deployed Rack code includes commit 4c4ea296fdfd115377912aa7dbcb55b83bf2888e or a package release known to include that fix. Review Gemfile.lock, vendored source, container images, and build artifacts to ensure the runtime application is not still using an affected Rack parser. In a controlled test environment, send malformed multipart requests with non-terminating part headers and verify they are rejected or bounded without unbounded memory growth. Monitor application memory during the test and confirm workers remain stable. Also verify upstream controls such as maximum request body size, header limits, upload limits, and request timeouts are active and applied before traffic reaches the application.
Typical attack path
- Identify a Rack-based web application or API endpoint that accepts multipart/form-data requests.
- Send a multipart request with a valid-looking boundary and a part header block that does not terminate correctly with the required blank line.
- Continue streaming or sending body bytes so the parser accumulates data while waiting for the missing header terminator.
- Repeat the malformed requests concurrently or over time to increase memory pressure on application workers.
- Cause degraded performance, request failures, worker crashes, container restarts, or host-level out-of-memory events.
How to detect it
Look for evidence of denial-of-service activity rather than a unique exploit artifact. Review web server, reverse proxy, WAF, application server, Rack/Ruby application, container runtime, and host kernel logs for bursts of multipart/form-data requests that end in 4xx/5xx responses, unusually long request durations, client disconnects, or large request bodies. Correlate those requests with memory spikes, Ruby worker crashes, application restarts, container restarts, kernel OOM-killer messages, and Ruby NoMemoryError or failed allocation errors. Pay particular attention to POST or PUT requests to upload/form endpoints where Content-Type is multipart/form-data and the request size or duration is abnormal. Because the malformed condition may not be fully logged by default, absence of a distinctive payload string does not rule out exploitation; correlation between multipart traffic and memory exhaustion is the strongest indicator.
- Content-Type: multipart/form-data
- multipart/form-data; boundary=
- Rack::Multipart::Parser
- NoMemoryError
- failed to allocate memory
- Cannot allocate memory
- out of memory
- OOMKilled
- oom-kill
- Killed process
- signal 9
- worker timeout
- worker restart
- upstream prematurely closed connection
- client prematurely closed connection
What your security team should do
- Inventory Rack-based applications, especially Ruby/Rails services, APIs, and upload-enabled endpoints that parse multipart/form-data.
- Prioritize patching internet-facing and high-traffic services even though the provided EPSS is low and the issue is not listed in KEV.
- Upgrade Rack or ensure deployments include commit 4c4ea296fdfd115377912aa7dbcb55b83bf2888e or later fixed code.
- Add or verify reverse-proxy, WAF, load-balancer, and application-server limits for request size, upload size, request duration, and concurrent connections.
- Search recent logs and telemetry for abnormal spikes in multipart POST requests, long-running upload requests, memory exhaustion, worker restarts, and OOM-kill events.
- Create monitoring alerts for sudden memory growth in Ruby application workers correlated with multipart/form-data traffic.
- If immediate patching is not possible, temporarily restrict upload endpoints, require authentication where feasible, and apply aggressive request limits at the edge.
The record
`Rack::Multipart::Parser` can accumulate unbounded data when a multipart part’s header block never terminates with the required blank line (`CRLFCRLF`). The parser keeps appending incoming bytes to memory without a size cap, allowing a remote attacker to exhaust memory and cause a denial of service (DoS).
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|---|---|---|
| RubyGems | rack | 0 | 2.2.19 |
| RubyGems | rack | 3.1 | 3.1.17 |
| RubyGems | rack | 3.2 | 3.2.2 |
| AlmaLinux:10 | cockpit-ha-cluster | 0 | 0.12.1-1.el10_1.1 |
| AlmaLinux:10 | pcs | 0 | 0.12.1-1.el10_1.1 |
| AlmaLinux:10 | pcs-snmp | 0 | 0.12.1-1.el10_1.1 |
| AlmaLinux:8 | pcs | 0 | 0.10.18-2.el8_10.7.alma.1 |
| AlmaLinux:8 | pcs-snmp | 0 | 0.10.18-2.el8_10.7.alma.1 |
| AlmaLinux:9 | pcs | 0 | 0.11.10-1.el9_7.1 |
| AlmaLinux:9 | pcs-snmp | 0 | 0.11.10-1.el9_7.1 |
| Chainguard | gitaly-config-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitaly-config-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitaly-config-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-base-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-base-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-base-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-certificates-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-certificates-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-certificates-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-cfssl-self-sign-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-cfssl-self-sign-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-cfssl-self-sign-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-cng-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-cng-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-cng-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-container-registry-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-container-registry-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-container-registry-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-container-registry-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-container-registry-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-container-registry-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-exporter-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-exporter-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-exporter-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-exporter-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-exporter-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-exporter-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-gitaly-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-gitaly-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-gitaly-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-logger-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-logger-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-logger-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-logger-compat-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-logger-compat-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-pages-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-pages-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-pages-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-rails-ce-18.1 | 0 | 18.1.6-r3 |
| Chainguard | gitlab-rails-ce-18.2 | 0 | 18.2.8-r3 |
| Chainguard | gitlab-rails-ce-18.3 | 0 | 18.3.6-r0 |
| Chainguard | gitlab-rails-ce-18.4 | 0 | 18.4.4-r0 |
| Chainguard | gitlab-rails-ce-18.5 | 0 | 18.5.2-r0 |
| Chainguard | gitlab-rails-ce-assets-18.1 | 0 | 18.1.6-r1 |
| Chainguard | gitlab-rails-ce-assets-18.2 | 0 | 18.2.8-r1 |
| Chainguard | gitlab-rails-ce-assets-18.3 | 0 | 18.3.5-r0 |
| Chainguard | gitlab-rails-ce-assets-18.4 | 0 | 18.4.3-r0 |
| Chainguard | gitlab-rails-ce-assets-18.5 | 0 | 18.5.1-r0 |
| Chainguard | gitlab-rails-ce-assets-fips-18.1 | 0 | 18.1.6-r2 |
| Chainguard | gitlab-rails-ce-assets-fips-18.2 | 0 | 18.2.8-r2 |
| Chainguard | gitlab-rails-ce-assets-fips-18.3 | 0 | 18.3.5-r2 |
| Chainguard | gitlab-rails-ce-assets-fips-18.4 | 0 | 18.4.3-r3 |
| Chainguard | gitlab-rails-ce-assets-fips-18.5 | 0 | 18.5.1-r2 |
| Chainguard | gitlab-rails-ce-doc-18.1 | 0 | 18.1.6-r1 |
| Chainguard | gitlab-rails-ce-doc-18.2 | 0 | 18.2.8-r1 |
| Chainguard | gitlab-rails-ce-doc-18.3 | 0 | 18.3.5-r0 |
| Chainguard | gitlab-rails-ce-doc-18.4 | 0 | 18.4.3-r0 |
| Chainguard | gitlab-rails-ce-doc-18.5 | 0 | 18.5.1-r0 |
| Chainguard | gitlab-rails-ce-doc-fips-18.1 | 0 | 18.1.6-r2 |
| Chainguard | gitlab-rails-ce-doc-fips-18.2 | 0 | 18.2.8-r2 |
| Chainguard | gitlab-rails-ce-doc-fips-18.3 | 0 | 18.3.5-r2 |
| Chainguard | gitlab-rails-ce-doc-fips-18.4 | 0 | 18.4.3-r3 |
| Chainguard | gitlab-rails-ce-doc-fips-18.5 | 0 | 18.5.1-r2 |
| Chainguard | gitlab-rails-ce-fips-18.1 | 0 | 18.1.6-r4 |
| Chainguard | gitlab-rails-ce-fips-18.2 | 0 | 18.2.8-r4 |
| Chainguard | gitlab-rails-ce-fips-18.3 | 0 | 18.3.6-r0 |
| Chainguard | gitlab-rails-ce-fips-18.4 | 0 | 18.4.4-r0 |
| Chainguard | gitlab-rails-ce-fips-18.5 | 0 | 18.5.2-r0 |
| Chainguard | gitlab-rails-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-rails-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-rails-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-shell-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-shell-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-shell-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-shell-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-shell-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-shell-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-shell-scripts-compat-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-shell-scripts-compat-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-sidekiq-ce-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-sidekiq-ce-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-sidekiq-ce-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-toolbox-ce-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-toolbox-ce-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-toolbox-ce-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-webservice-ce-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-webservice-ce-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-webservice-ce-18.4 | 0 | 18.4.2-r0 |
| Chainguard | gitlab-workhorse-scripts-18.2 | 0 | 18.2.8-r0 |
| Chainguard | gitlab-workhorse-scripts-18.3 | 0 | 18.3.4-r0 |
| Chainguard | gitlab-workhorse-scripts-18.4 | 0 | 18.4.2-r0 |
| Chainguard | logstash-8.17 | 0 | 8.17.10-r3 |
| Chainguard | logstash-8.17-bitnami-compat | 0 | 8.17.10-r3 |
| Chainguard | logstash-8.17-compat | 0 | 8.17.10-r3 |
| Chainguard | logstash-8.17-env2yaml | 0 | 8.17.10-r3 |
| Chainguard | logstash-8.17-iamguarded-compat | 0 | 8.17.10-r3 |
| Chainguard | logstash-8.17-with-output-opensearch | 0 | 8.17.10-r3 |
| Chainguard | logstash-8.18 | 0 | 8.18.8-r1 |
| Chainguard | logstash-8.18-bitnami-compat | 0 | 8.18.8-r1 |
| Chainguard | logstash-8.18-compat | 0 | 8.18.8-r1 |
| Chainguard | logstash-8.18-env2yaml | 0 | 8.18.8-r1 |
| Chainguard | logstash-8.18-iamguarded-compat | 0 | 8.18.8-r1 |
| Chainguard | logstash-8.18-with-output-opensearch | 0 | 8.18.8-r1 |
| Chainguard | logstash-8.19 | 0 | 8.19.5-r1 |
| Chainguard | logstash-8.19-compat | 0 | 8.19.5-r1 |
| Chainguard | logstash-8.19-env2yaml | 0 | 8.19.5-r1 |
| Chainguard | logstash-8.19-iamguarded-compat | 0 | 8.19.5-r1 |
| Chainguard | logstash-8.19-with-output-opensearch | 0 | 8.19.5-r1 |
| Chainguard | logstash-9.0 | 0 | 9.0.8-r1 |
| Chainguard | logstash-9.0-bitnami-compat | 0 | 9.0.8-r1 |
| Chainguard | logstash-9.0-compat | 0 | 9.0.8-r1 |
| Chainguard | logstash-9.0-env2yaml | 0 | 9.0.8-r1 |
| Chainguard | logstash-9.0-iamguarded-compat | 0 | 9.0.8-r1 |
| Chainguard | logstash-9.0-with-output-opensearch | 0 | 9.0.8-r1 |
| Chainguard | logstash-9.1 | 0 | 9.1.5-r1 |
| Chainguard | logstash-9.1-bitnami-compat | 0 | 9.1.5-r1 |
| Chainguard | logstash-9.1-compat | 0 | 9.1.5-r1 |
| Chainguard | logstash-9.1-env2yaml | 0 | 9.1.5-r1 |
| Chainguard | logstash-9.1-iamguarded-compat | 0 | 9.1.5-r1 |
| Chainguard | logstash-9.1-with-output-opensearch | 0 | 9.1.5-r1 |
| Chainguard | ruby3.2-rails-7.1 | 0 | 7.1.6-r0 |
| Chainguard | ruby3.2-rails-7.1-compat | 0 | 7.1.6-r0 |
| Chainguard | ruby3.2-rails-7.2 | 0 | 7.2.2.2-r1 |
| Chainguard | ruby3.2-rails-7.2-compat | 0 | 7.2.2.2-r1 |
| Chainguard | ruby3.2-rails-8.0 | 0 | 8.0.3-r1 |
| Chainguard | ruby3.2-rails-8.0-compat | 0 | 8.0.3-r1 |
| Chainguard | ruby3.3-rack-2.2 | 0 | 2.2.22-r0 |
| Chainguard | ruby3.3-rails-7.1 | 0 | 7.1.6-r0 |
| Chainguard | ruby3.3-rails-7.1-compat | 0 | 7.1.6-r0 |
| Chainguard | ruby3.3-rails-7.2 | 0 | 7.2.2.2-r1 |
| Chainguard | ruby3.3-rails-7.2-compat | 0 | 7.2.2.2-r1 |
| Chainguard | ruby3.3-rails-8.0 | 0 | 8.0.3-r1 |
| Chainguard | ruby3.3-rails-8.0-compat | 0 | 8.0.3-r1 |
| Chainguard | ruby3.4-rails-7.1 | 0 | 7.1.6-r0 |
| Chainguard | ruby3.4-rails-7.1-compat | 0 | 7.1.6-r0 |
| Chainguard | ruby3.4-rails-7.2 | 0 | 7.2.2.2-r1 |
| Chainguard | ruby3.4-rails-7.2-compat | 0 | 7.2.2.2-r1 |
| Chainguard | ruby3.4-rails-8.0 | 0 | 8.0.3-r1 |
| Chainguard | ruby3.4-rails-8.0-compat | 0 | 8.0.3-r1 |
| Mageia:9 | ruby-rack | 0 | 2.2.21-1.mga9 |
| Wolfi | gitaly-config-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-base-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-certificates-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-cfssl-self-sign-scripts-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-cng-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-container-registry-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-container-registry-scripts-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-exporter-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-exporter-scripts-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-gitaly-scripts-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-logger-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-logger-compat-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-pages-scripts-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-shell-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-shell-scripts-18.2 | 0 | 18.2.8-r0 |
| Wolfi | gitlab-shell-scripts-compat-18.2 | 0 | 18.2.8-r0 |
| Wolfi | logstash-9.1 | 0 | 9.1.5-r1 |
| Wolfi | logstash-9.1-bitnami-compat | 0 | 9.1.5-r1 |
| Wolfi | logstash-9.1-compat | 0 | 9.1.5-r1 |
| Wolfi | logstash-9.1-env2yaml | 0 | 9.1.5-r1 |
| Wolfi | logstash-9.1-iamguarded-compat | 0 | 9.1.5-r1 |
| Wolfi | logstash-9.1-with-output-opensearch | 0 | 9.1.5-r1 |
| Wolfi | ruby3.2-rails-8.0 | 0 | 8.0.3-r1 |
| Wolfi | ruby3.2-rails-8.0-compat | 0 | 8.0.3-r1 |
| Wolfi | ruby3.3-rack-2.2 | 0 | 2.2.22-r0 |
| Wolfi | ruby3.3-rails-8.0 | 0 | 8.0.3-r1 |
| Wolfi | ruby3.3-rails-8.0-compat | 0 | 8.0.3-r1 |
| Wolfi | ruby3.4-rails-8.0 | 0 | 8.0.3-r1 |
| Wolfi | ruby3.4-rails-8.0-compat | 0 | 8.0.3-r1 |
| gem | rack | 3.1 | 3.1.17 |
| gem | rack | 3.2 | 3.2.2 |
| openSUSE:Tumbleweed | rubygem-rack-2.2 | 0 | 2.2.19-1.1 |
| openSUSE:Tumbleweed | rubygem-rack-2.2 | 0 | 2.2.22-1.1 |
Related vulnerabilities
- CVE-2026-25500 Rack is a modular Ruby web server interface. Also affects rack
- CVE-2026-22860 Rack is a modular Ruby web server interface. Also affects rack
- CVE-2025-61919 Rack is vulnerable to a memory-exhaustion DoS through unbounded URL-encoded body parsing Also affects rack
- CVE-2025-61780 Rack has a Possible Information Disclosure Vulnerability Also affects rack
- CVE-2025-61770 Rack's unbounded multipart preamble buffering enables DoS (memory exhaustion) Also affects rack
- CVE-2025-61771 Rack: Multipart parser buffers large non‑file fields entirely in memory, enabling DoS… Also affects rack
- CVE-2025-59830 Rack has an unsafe default in Rack::QueryParser allows params_limit bypass via… Also affects rack
- CVE-2025-46336 Rack::Session is a session management implementation for Rack. Also affects rack