Bug 2536976 (CVE-2026-93563) - CVE-2026-93563 io.netty/netty-codec-smtp: Netty: Unbounded multi-line response accumulation in SmtpResponseDecoder leads to memory-exhaustion DoS
Summary: CVE-2026-93563 io.netty/netty-codec-smtp: Netty: Unbounded multi-line respons...
Keywords:
Status: NEW
Alias: CVE-2026-93563
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
high
high
Target Milestone: ---
Assignee: Product Security
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-09-18 10:43 UTC by OSIDB Bzimport
Modified: 2026-09-18 20:01 UTC (History)
37 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-09-18 10:43:18 UTC
Unbounded multi-line response accumulation in SmtpResponseDecoder leads to memory-exhaustion DoS

A public GitHub Security Advisory (GHSA-pq4x-537v-r54q) describes the following issue:

## Summary
`io.netty.handler.codec.smtp.SmtpResponseDecoder` accumulates the multi-line `details` of an SMTP response into a per-connection `ArrayList<CharSequence>` that has NO count or cumulative-size cap. A malicious or MITM SMTP server that withholds the space-separated terminator line and streams unbounded `250-x\r\n` continuation lines drives that list to grow without bound across `decode()` invocations, exhausting the JVM heap and killing the Netty-based SMTP client/MTA process (Denial of Service).

## Root Cause
`this.details` (`SmtpResponseDecoder.java:35`, `ArrayList<CharSequence>`) is written only at `:66` (set to `null` on the terminator), `:85` (new list), and `:87` (`add`). A `grep` of the file for `maxNum`/`size()`/any cumulative cap returns only `maxLineLength` — a per-line bound, not an aggregate one. Accumulation resets ONLY on the space-separator branch (`:64`, resets `this.details=null` at `:66`); the `'-'` continuation branch (`:79-89`) never resets or caps. A server that sends only `250-x\r\n` (continuation) and never `250 x\r\n` (terminator) grows `details` forever. The decoded per-line frame is released at `:94`, but the retained `String` copies (`:59`) in `details` are not, so nothing frees the accumulated memory. `LineBasedFrameDecoder.maxLength` (`LineBasedFrameDecoder.java:44-45,:112`) bounds only each individual line — no aggregate/message-level cap exists anywhere in the module.

This is the unpatched structural sibling of CVE-2026-44891, which added a `maxNumHeaders` cap to `StompSubframeDecoder` (the only other `LineBasedFrameDecoder` subclass). `SmtpResponseDecoder` was never given the analogous cap. It is also the same bug class Netty already published at MEDIUM in GHSA-q4f6-jm68-57ww (unbounded per-connection queue growth -> DoS).

## Impact
Heap exhaustion -> `OutOfMemoryError` -> total availability loss (process crash) of the SMTP client/MTA. Client-side decoder: the attacker must occupy the server side of the connection (attacker-controlled MX for direct-to-MX delivery, user/tenant-supplied SMTP host, mail-testing tooling, or a STARTTLS-downgrade MITM on cleartext SMTP).

## Proof of Concept
Stand up an SMTP listener that, upon any client connection, repeatedly writes `250-x\r\n` and never sends a space-separated terminator (`250 x\r\n`). Point a Netty pipeline containing `SmtpResponseDecoder` at it. `details` grows one retained `String` (~40-60 bytes) per 7-byte line until the client heap is exhausted.

## Attack Chain
1. Entry: a Netty-based SMTP client/MTA (pipeline contains `SmtpResponseDecoder`) opens a connection to an attacker-controlled or MITM'd SMTP server.
   - Guard: none at connect; TLS is no barrier when the attacker owns the endpoint or downgrades STARTTLS on cleartext SMTP.
   - Bypass proof: the class is client-side by construction (decodes server responses; `SmtpResponseDecoderTest.java:148` instantiates it for inbound decoding). MTAs connect to remote-controlled MX servers by design.
2. Check/Feed continuation lines: server streams `250-x\r\n` (7 bytes, non-empty detail) repeatedly, each below `maxLineLength`.
   - Guard: `LineBasedFrameDecoder.maxLength` per-line bound (`LineBasedFrameDecoder.java:112`).
   - Bypass proof: each 7-byte line is far below `maxLineLength`; the check never inspects `details`. Every line takes the `'-'` branch (`:79`) -> `details.add(detail)` (`:87`).
3. Withhold terminator: server never sends the space-separated `250 x\r\n` line.
   - Guard: the only reset of `this.details` is the space branch at `:66`; there is no count/size cap on the `'-'` path.
   - Bypass proof: writes to `this.details` occur only at `:66` (null), `:85` (new), `:87` (add) - confirmed by grep; no `details.size()`/`maxNum` check exists. `details` is an instance field (`:35`) persisting across `decode()` calls.
4. Sink: `this.details` and its retained `String` elements grow without bound across `decode()` invocations (`:87`).
   - Guard: none - no aggregate frame/message limit; the per-line frame is released at `:94` but the retained `String` copy (`:59`) is not.
   - Bypass proof: `LineBasedFrameDecoder` bounds only per-line length; nothing caps cumulative retained objects.
5. Impact: `OutOfMemoryError` -> DoS of the SMTP client/MTA process.

## Bypass Evidence
- On latest release tag `netty-4.2.16.Final`, `git show netty-4.2.16.Final:.../SmtpResponseDecoder.java` shows `new ArrayList<CharSequence>(4)` (:85) and `details.add(detail)` (:69/:87) with NO cap; only `maxLineLength` is present.
- `grep -rnE "maxNum|maxDetails|maxLines|TooLongFrameException" codec-smtp/` returns NONE — no aggregate cap anywhere in the module.
- `git log netty-4.2.16.Final..HEAD -- SmtpResponseDecoder.java` is empty — no post-release fix.
- Contrast: the sibling `StompSubframeDecoder` HAS `maxNumHeaders` -> `TooLongFrameException`; SMTP has no equivalent.
- Dedup clean: netty's published advisories contain no `SmtpResponseDecoder`/codec-smtp memory-exhaustion entry (the only codec-smtp advisory, GHSA-jq43-27x9-3v86, is SMTP command injection — a different class).

## Affected Versions
`io.netty:netty-codec-smtp` `<= 4.2.16.Final` (all released versions; the 4.1.x line is likewise affected — the decoder has had no aggregate cap since its 2016 introduction).

## Suggested Fix
Add a `maxNumLines` (and/or cumulative-detail-size) parameter to `SmtpResponseDecoder`, incrementing per continuation line and throwing `TooLongFrameException` when exceeded — mirroring `StompSubframeDecoder`'s `maxNumHeaders`. Provide a safe default (e.g., 128) via an overloaded constructor.

---
Reported by **zx (Jace)** — GitHub: @manus-use

Affected:
- maven:io.netty:netty-codec-smtp affected >= 4.2.0.Final, <= 4.2.17.Final; fixed unknown
- maven:io.netty:netty-codec-smtp affected >= 4.1.0.Final, <= 4.1.137.Final; fixed unknown

Fixed versions: see advisory

Advisory: https://github.com/netty/netty/security/advisories/GHSA-pq4x-537v-r54q


Note You need to log in before you can comment on or make changes to this bug.