Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-49755

CVE-2026-49755: Req (Elixir) DOS Vulnerability

CVE-2026-49755 is a denial of service vulnerability in Req that allows attacker-controlled servers to exhaust memory via decompression bombs. This post covers technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-49755 Overview

CVE-2026-49755 is a data amplification vulnerability in the wojtekmach/req HTTP client for Elixir. The flaw allows an attacker-controlled HTTP server to exhaust memory in a Req client by returning decompression-bomb response bodies. Req's default response pipeline performs automatic body decoding and decompression without size limits, so a sub-megabyte response can expand to multiple gigabytes on the victim and crash the BEAM virtual machine process. The vulnerability affects all req versions from 0.1.0 up to but not including 0.6.1. It is tracked under CWE-409: Improper Handling of Highly Compressed Data.

Critical Impact

A single attacker-controlled HTTP response can trigger gigabyte-scale memory allocation on the client, crashing the Erlang VM and producing a denial-of-service condition on any Elixir service that issues outbound Req requests.

Affected Products

  • wojtekmach/req HTTP client for Elixir, versions >= 0.1.0 and < 0.6.1
  • Any Elixir or Erlang application that uses Req for outbound HTTP requests with default settings
  • Applications that follow redirects via Req to untrusted hosts

Discovery Timeline

  • 2026-06-08 - CVE-2026-49755 published to NVD
  • 2026-06-09 - Last updated in NVD database

Technical Details for CVE-2026-49755

Vulnerability Analysis

The vulnerability resides in Req's default response pipeline, specifically the Req.Steps.decode_body/1 and Req.Steps.decompress_body/1 functions in lib/req/steps.ex. Both steps run by default and require no caller opt-in. The attacker controls the content-type and content-encoding headers returned by their own HTTP server, or any host reached through Req's automatic redirect following.

decode_body/1 dispatches on the server-supplied content type or URL extension. For application/zip it calls :zip.extract(body, [:memory]). For application/x-tar it calls :erl_tar.extract({:binary, body}, [:memory]). For application/gzip and .tgz it calls :erl_tar.extract({:binary, body}, [:memory, :compressed]). Each call returns the full decompressed archive contents as an in-memory [{name, bytes}] list with no per-entry or total size cap.

decompress_body/1 walks the content-encoding header and chains :zlib, :brotli, and :ezstd decoders. A response advertising content-encoding: gzip, gzip, gzip inflates through multiple layers without bound. The amplification ratio between the bytes received on the wire and the bytes allocated in the BEAM heap is unbounded.

Root Cause

The root cause is missing size enforcement around streaming decompression and archive extraction. The pipeline trusts attacker-supplied headers and treats archive entries as opaque byte lists rather than streaming them with a budget. No upper bound is enforced on cumulative decompressed size or on the depth of chained encodings.

Attack Vector

The attack vector is network-based and requires no authentication or user interaction. An attacker hosts a malicious HTTP endpoint, or compromises one already reachable from the victim via redirect. When the Req-based client issues a request, the server returns a small compressed payload with crafted content-type and content-encoding headers. The client decompresses the payload into multiple gigabytes of memory and the BEAM process crashes.

text
// Source: https://github.com/wojtekmach/req/commit/84977e5b1a83f26e749d55ad06e3625464af4e8d
// Patch to lib/req.ex - documentation reflecting behavioral change

Response body options:

-    * `:compressed` - if set to `true`, asks the server to return compressed response.
-      (via [`compressed`](`Req.Steps.compressed/1`) step.) Defaults to `true`.
+    * `:compressed` - if set to `true`, asks the server to return a compressed response and
+      decompresses it (via the [`compressed`](`Req.Steps.compressed/1`) and
+      [`decompress_body`](`Req.Steps.decompress_body/1`) steps.) Defaults to `false`.

-    * `:raw` - if set to `true`, disables automatic body decompression
-      ([`decompress_body`](`Req.Steps.decompress_body/1`) step) and decoding
+    * `:raw` - if set to `true`, disables body decompression
+      ([`decompress_body`](`Req.Steps.decompress_body/1`) step) and automatic decoding
       ([`decode_body`](`Req.Steps.decode_body/1`) step.) Defaults to `false`.

The patch disables automatic decompression by default. Callers must now opt in by setting :compressed to true, which restores the previous behavior at the caller's explicit risk.

Detection Methods for CVE-2026-49755

Indicators of Compromise

  • Sudden BEAM process crashes with out-of-memory errors on hosts running Elixir services that perform outbound HTTP requests
  • Resident set size (RSS) spikes from megabytes to gigabytes within seconds, followed by OS-level OOM kills
  • HTTP responses where the Content-Length is small but the Content-Encoding chains multiple algorithms such as gzip, gzip, gzip
  • Outbound requests to untrusted hosts returning archive content types (application/zip, application/x-tar, application/gzip) that are not expected by the application

Detection Strategies

  • Audit dependency manifests (mix.exs, mix.lock) for req versions earlier than 0.6.1 across all Elixir projects in the organization
  • Inspect application logs for enomem errors, :erl_tar.extract or :zip.extract stack frames, and abnormal supervisor restarts
  • Correlate process exits with outbound HTTP traffic patterns using egress proxy or NetFlow data
  • Use software composition analysis (SCA) tooling to flag the GitHub advisory GHSA-655f-mp8p-96gv

Monitoring Recommendations

  • Track per-process memory growth on BEAM nodes and alert when allocation rate exceeds an established baseline
  • Log every outbound HTTP response's Content-Encoding and Content-Type headers from Req-based services for retrospective hunting
  • Monitor for repeated container or systemd unit restarts caused by OOM kills on services issuing outbound HTTP traffic
  • Forward Elixir crash dumps and :erlang.system_info snapshots to a central log store for analysis

How to Mitigate CVE-2026-49755

Immediate Actions Required

  • Upgrade req to version 0.6.1 or later in all Elixir projects and rebuild release artifacts
  • For applications that cannot upgrade immediately, set raw: true on every Req request or remove decode_body and decompress_body from the pipeline
  • Disable automatic redirect following with redirect: false when calling untrusted hosts to prevent attacker pivots through trusted endpoints
  • Restrict outbound HTTP egress from Elixir services to known, trusted destinations via network policy

Patch Information

The fix is committed in wojtekmach/req commit 84977e5b and released in version 0.6.1. The patch changes the default value of the :compressed option from true to false, so Req no longer requests or transparently decompresses responses unless the caller opts in. Full details are in the GitHub Security Advisory GHSA-655f-mp8p-96gv and the Erlang Ecosystem Foundation CNA record.

Workarounds

  • Pass raw: true to every Req.request/2 call to bypass decode_body and decompress_body until the upgrade is deployed
  • Wrap Req calls in a supervised, memory-limited worker process so an OOM in the worker does not destabilize the parent application
  • Validate Content-Type and Content-Encoding headers in a custom Req step and reject responses with chained encodings or unexpected archive types
  • Enforce response size limits at the HTTP transport layer using Req adapter options such as Finch pool configuration with hard byte caps
bash
# Upgrade Req to the patched release in mix.exs
# {:req, "~> 0.6.1"}

mix deps.update req
mix deps.get
mix compile --force

# Verify the resolved version
mix deps | grep req

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.