GHSA-655f-mp8p-96gv

Suggest an improvement
Source
https://github.com/advisories/GHSA-655f-mp8p-96gv
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-655f-mp8p-96gv/GHSA-655f-mp8p-96gv.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-655f-mp8p-96gv
Aliases
Published
2026-07-29T15:23:16Z
Modified
2026-07-29T15:30:39Z
Severity
  • 8.2 (High) CVSS_V4 - CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N CVSS Calculator
Summary
Req vulnerable to unbounded archive/compression extraction triggered by response content-type
Details

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

  1. Run an HTTP server that responds 200 with content-type: application/zip and a body that is a zip archive whose single entry is ~400 MB of zero bytes (compressed wire payload: a few hundred KB).
  2. From the victim process, call Req.get!(url) against that server (no special options, no opt-in to archive decoding).
  3. decode_body/1 dispatches on content-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 the content-encoding path 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.

Database specific
{
    "cwe_ids": [
        "CWE-409"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-29T15:23:16Z",
    "nvd_published_at": "2026-06-08T16:16:43Z",
    "severity": "HIGH"
}
References

Affected packages

Hex / req

Package

Name
req
Purl
pkg:hex/req

Affected ranges

Type
SEMVER
Events
Introduced
0.1.0
Fixed
0.6.1

Affected versions

0.*
0.1.0
0.1.1
0.1.2
0.2.0
0.2.1
0.2.2
0.3.0
0.3.1
0.3.2
0.3.3
0.3.4
0.3.5
0.3.6
0.3.7
0.3.8
0.3.9
0.3.10
0.3.11
0.3.12
0.4.0
0.4.1
0.4.2
0.4.3
0.4.4
0.4.5
0.4.6
0.4.7
0.4.8
0.4.9
0.4.10
0.4.11
0.4.12
0.4.13
0.4.14
0.5.0
0.5.1
0.5.2
0.5.3
0.5.4
0.5.5
0.5.6
0.5.7
0.5.8
0.5.9
0.5.10
0.5.11
0.5.12
0.5.13
0.5.14
0.5.15
0.5.16
0.5.17
0.5.18
0.6.0

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-655f-mp8p-96gv/GHSA-655f-mp8p-96gv.json"