CVE-2026-48594 Root-Cause Patch Review for Tesla Compression Middleware
Summary
Tesla’s patch addresses the denial-of-service condition by making decompression limits explicit, switching from one-shot decompression to bounded streaming inflation, and rejecting multiple supported content-encoding layers that amplify decompression bombs. The change materially improves safety and converts previously implicit unsafe behavior into an opt-in model for unbounded decompression.
Analysis
Vulnerability
CVE-2026-48594 is a denial-of-service issue in Tesla’s compression middleware where untrusted HTTP response bodies were decompressed without an enforced output bound and with recursive handling of multiple content encodings. In the vulnerable implementation, gzip and deflate payloads were expanded via one-shot calls such as :zlib.gunzip(body) and :zlib.unzip(body), then recursively passed back into decompress_body/2. That design allowed a remote server to return a very small compressed payload that inflated into a much larger in-memory body, exhausting heap memory and potentially crashing the BEAM VM. The issue and fix are documented in the upstream commit, advisory, and CVE records: upstream patch commit, GHSA advisory, NVD, and CVE record.
defp decompress_body([gzip | rest], body) when gzip in ["gzip", "x-gzip"] do
decompress_body(rest, :zlib.gunzip(body))
end
defp decompress_body(["deflate" | rest], body) do
decompress_body(rest, :zlib.unzip(body))
endThe vulnerable pattern is not just lack of a size limit; it also permits repeated supported codecs in content-encoding, which compounds expansion risk by recursively decoding multiple layers. The tests in the patch show prior acceptance of multi-encoding responses and the new security posture around stacked codecs.
Patch
The patch introduces three substantive controls. First, it requires callers to set :max_body_size, rejecting middleware configuration that omits a decompression cap unless the caller explicitly opts out with :infinity. Second, it replaces one-shot decompression with a streaming inflate path using zlib state, described in the patch as using :zlib.safeInflate/2 semantics to stop once the configured output limit is exceeded, before materializing the full decompressed body. Third, it rejects responses that advertise more than one supported compression codec in content-encoding, raising a middleware-specific error for stacked codec patterns such as gzip, gzip or gzip, deflate.
def decompress(env, opts) do
max_body_size = fetch_max_body_size!(opts)
if count_known_codecs(codecs) > 1 do
raise Error, reason: :multiple_codecs
end
{decompressed_body, unknown_codecs} = decompress_body(codecs, env.body, max_body_size)
end
defp fetch_max_body_size!(opts) do
case Keyword.fetch(opts || [], :max_body_size) do
{:ok, :infinity} -> :infinity
{:ok, size} when is_integer(size) and size > 0 -> size
:error ->
raise ArgumentError,
"Tesla.Middleware.Compression requires the :max_body_size option to be set."
end
endThe patch also adds a dedicated Tesla.Middleware.Compression.Error exception with structured reasons including :max_body_size_exceeded, :multiple_codecs, and zlib-originated failures. Test coverage was expanded to validate bounded decompression, mandatory configuration, explicit :infinity opt-out, and rejection of stacked supported codecs. These changes are visible in the upstream commit and advisory: commit 340f75b and GHSA-MC85-72GR-VM9F.
Review
Pros
The patch addresses the core memory-exhaustion primitive rather than only filtering specific payloads. Requiring :max_body_size makes decompression risk an explicit configuration decision and prevents silent insecure defaults. The move away from :zlib.gunzip/1 and :zlib.unzip/1 toward bounded streaming inflation is the most important technical improvement because it allows the middleware to terminate expansion once the output cap is crossed, instead of allocating the full inflated body first. Rejecting more than one supported codec also closes the recursive amplification path that previously allowed repeated decompression passes. The new exception type improves failure handling for callers and the tests demonstrate the intended security invariants, including bomb-style payloads and stacked codec rejection.
Cons
The patch intentionally narrows protocol permissiveness by rejecting any response with more than one supported codec, even though multiple content codings can be valid in HTTP. That is a security-first tradeoff, but it may break interoperability for edge deployments that legitimately stack supported encodings. The explicit :infinity escape hatch preserves backward compatibility for users who need old behavior, but it also means unsafe operation remains available by configuration. The reviewable snippet does not expose the full inflate/3 implementation, so correctness of the exact bounded streaming loop and whether all intermediate buffers are tightly accounted for must be inferred from the commit summary and tests rather than fully verified from the excerpt alone. Finally, unknown codecs are still preserved rather than rejected outright, which is reasonable for compatibility but means downstream middleware behavior still depends on header rewriting correctness.
Verdict
Root-cause.
This patch fixes the underlying denial-of-service mechanism by enforcing a decompressed-size policy at the middleware boundary and by changing the decompression strategy from unbounded one-shot expansion to bounded streaming inflation. It also removes the recursive multi-supported-codec path that materially increased amplification risk. The remaining concerns are compatibility and the presence of an explicit unsafe opt-out, not an obvious residual bypass in the patched default model. For engineering teams, this is a strong security patch that should be adopted together with a consciously chosen max_body_size appropriate to expected response sizes. References: patch commit, official advisory, NVD entry, MITRE CVE record, report context.
Recommended Labs
Try this vulnerability pattern yourself with hands-on labs.
- Untar.py
Closest defensive hands-on match to this CVE’s root cause. Although the Tesla issue is an Elixir HTTP decompression bomb rather than archive extraction, this lab trains the same secure-coding instinct: never trust compressed input, validate before expanding, and apply safe handling to attacker-controlled content to prevent downstream abuse.
- BadZip.go
A stronger follow-on lab for practicing defensive handling of archive and extraction logic. It helps build threat awareness around unsafe expansion paths, attacker-controlled compressed content, and the need for guardrails such as limits, validation, and safe extraction patterns—concepts directly relevant to decompression-bomb resilience.
- XXE Injection.py
Not a decompression lab, but highly relevant as a defensive parser-hardening exercise. Decompression bombs and recursive codec issues share the same broader lesson as XXE: parser and decoder features can become denial-of-service vectors if expansion, recursion, or entity processing is left unconstrained. Good supporting practice for secure middleware and client response handling.