CVE-2026-49755 — req
Fix: wojtekmach/req@84977e5CVE-2026-49755 is a CWE-409 vulnerability in req. A fix is available for req — see the affected versions and patch details below.
Decompression bomb DoS in Req via auto-decoded archive and compressed response bodies
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-49755.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
reqReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Hex packages — download data is not available via public APIs for these ecosystems.
Description
Summary
Req's default response pipeline auto-decodes archive and compressed bodies based on the server-supplied content-type (or URL extension) and materialises the full decompressed contents in memory with no size cap. An attacker who controls (or can redirect a victim into) an HTTP endpoint reached by Req.get!/1 can return a tiny "decompression bomb" that expands to many gigabytes on the client and exhausts the BEAM's memory.
Details
1. Archive auto-decoding. Req.Steps.decode_body/1 in lib/req/steps.ex dispatches on the response content-type (or URL extension) and calls Erlang's archive libraries with :memory, returning a [{name, bytes}] list of every entry fully decompressed in RAM: application/zip → :zip.extract(body, [:memory]), application/x-tar → :erl_tar.extract({:binary, body}, [:memory]), application/gzip / .tgz → :erl_tar.extract({:binary, body}, [:memory, :compressed]). No byte cap is enforced before decoding and no per-entry size limit is passed to :zip / :erl_tar.
2. content-encoding chaining. Req.Steps.decompress_body/1 walks the content-encoding header and chains :zlib / :brotli / :ezstd decoders, so a response advertising content-encoding: gzip, gzip, gzip, … inflates through multiple layers without bound.
3. Default-on, attacker-chosen decoder. Both steps are part of Req's default pipeline. The caller does not need to opt in, and the attacker chooses which decoder fires by setting content-type and content-encoding on their own server (or on any host reached via Req's automatic redirect following).
PoC
- Run an HTTP server that responds 200 with
content-type: application/zipand a body that is a zip archive whose single entry is ~400 MB of zero bytes (compressed wire payload: a few hundred KB). - From the victim process, call
Req.get!(url)against that server (no special options, no opt-in to archive decoding). decode_body/1dispatches oncontent-type, invokes:zip.extract(body, [:memory]), and the response body becomes[{~c"bomb.bin", <<400 MB of zero bytes>>}]. A sub-MB request produces hundreds of MB resident memory; layering gzip on thecontent-encodingpath or increasing entry size scales arbitrarily.
Impact
Memory-exhaustion denial of service against any Elixir application that uses Req with its default step pipeline to fetch URLs influenced by an untrusted party, including webhook senders, link previews, OAuth/OIDC discovery clients, package mirrors, image proxies, and any Req.get!/1 call that may follow redirects to attacker-controlled hosts. No authentication is required; a single response can crash the BEAM and take down unrelated workloads on the same VM.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 💧Hex | req | ≥ 0.1.0&&< 0.6.1 | 0.6.1mix deps.update req |
Affected Products
reqwojtekmachDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for req, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update req to 0.6.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-49755 is resolved across your whole dependency graph.
Workarounds
Cap what an attacker can consume: apply request size, rate and timeout limits in front of the affected component, and run it with memory and CPU limits so exhaustion degrades one worker rather than the whole service.
Frequently Asked Questions
Is CVE-2026-49755 in your dependencies?
Find it across Hex, including transitive dependencies.