IMAP COMPRESS=DEFLATE permits a 1,000x response-line decompression bomb
Categories
(MailNews Core :: Networking: IMAP, defect)
Tracking
(Not tracked)
People
(Reporter: tjddbdud1, Assigned: olav)
References
Details
Attachments
(1 file, 1 external file)
|
19.81 KB,
application/x-zip-compressed
|
Details |
Summary
Thunderbird enables IMAP COMPRESS=DEFLATE by default when a configured server advertises it. A malicious or compromised IMAP server can send a very small raw-DEFLATE stream that expands to a response without an LF. nsMsgCompressIStream incrementally inflates the stream, while nsMsgLineStreamBuffer::ReadNextLine() repeatedly grows its backing allocation until a line terminator appears. No decompressed logical-line size limit is enforced.
On the latest official Windows Daily, a 65,237-byte compressed response expanded to 64 MiB and raised resident memory by 119.39 MiB in about 2.4 seconds. The stream can be extended to exhaust available memory and make Thunderbird unresponsive or terminate it.
Security impact
A malicious IMAP provider, a compromised configured server, or an attacker who controls the account's IMAP endpoint can cause a disproportionate memory denial of service during an ordinary authenticated connection. Compression is enabled by default; after initial account configuration, normal background connection or folder expansion is sufficient to reach the vulnerable path.
Suggested severity: Moderate
- CWE-409 (Improper Handling of Highly Compressed Data / Zip Bomb)
- CWE-400 / CWE-770 (Uncontrolled Resource Consumption / Allocation Without Limits)
- CVSS 3.1:
AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H= 6.5
Tested build
- Thunderbird Daily 161.0a1, Windows x64
- Build ID:
20261103100812 - Source stamp:
c5b3416d323259549cb0d4e99ec64380ad45b697
This build includes the recent IMAP compression-transition fix from Bug 2087454. That fix feeds already-buffered compressed bytes into the inflater, but it does not impose a limit on the decompressed logical response line.
Reproduction
The attached zip contains a production-path xpcshell PoC, runner, source notes, raw logs, and exact measurements.
- Run
.\run.ps1 -MiB 32. - Observe that Thunderbird authenticates, requests
COMPRESS DEFLATE, and processes a 32,623-byte stream which expands to a 32 MiB unterminated logical line. - Run
.\run.ps1 -MiB 64. - Observe 65,237 bytes expanding to a 64 MiB unterminated logical line and a 119.39 MiB increase in resident memory.
| Expanded response | Compressed bytes | Ratio | Baseline RSS | Peak RSS | RSS growth |
|---|---|---|---|---|---|
| 32 MiB | 32,623 | 1,028.55x | 57.71 MiB | 122.39 MiB | 64.69 MiB |
| 64 MiB | 65,237 | 1,028.69x | 57.48 MiB | 176.87 MiB | 119.39 MiB |
Both included runs pass assertions that Thunderbird negotiated compression, the expansion ratio exceeds 500x, and resident-memory growth is material.
Root cause
mail.server.default.use_compress_deflateistrue.- After login,
nsImapProtocolautomatically sendsCOMPRESS DEFLATEwhen the capability is present. nsMsgCompressIStreaminflates raw DEFLATE into 16 KiB output chunks.nsImapProtocol::CreateNewLineFromSocket()passes the decompressed stream tonsMsgLineStreamBuffer::ReadNextLine().- When no LF is present,
ReadNextLine()repeatedly reallocates its backing buffer and appends decompressed chunks with no protocol-appropriate limit.
A timeout does not help because the server keeps delivering compressed data and the decompressor keeps producing bytes.
Nearby public bugs reviewed
- Bug 2087454 concerns compressed bytes already present at the compression transition bypassing the inflater and desynchronizing responses. It does not cap decompressed output or line length.
- Bug 1581017 concerns growth/crashes with unusually large ordinary IMAP responses and was closed WORKSFORME. It does not demonstrate a small compressed input producing ~1,000x output on the latest fixed compression path.
- Bug 1294074 is an old zlib crash signature associated with IMAP compression, not an attacker-controlled decompressed logical-line resource limit.
Suggested fix
Enforce a conservative maximum decompressed IMAP logical-line length before growing the line buffer, and terminate the connection with a protocol error when the limit is exceeded. The limit must be applied after decompression.
Please keep this report and attachment confidential until triage and a fix are complete.
AI assistance was used to help review source and prepare the test and report. All measurements were produced locally against the official build and the raw logs are attached.
Comment 1•11 days ago
|
||
Not much of a security issue, but we should probably fix it
| Assignee | ||
Comment 2•10 days ago
|
||
I'll take this one, since it's in the same code as bug 2087454.
Plan: give nsMsgLineStreamBuffer an optional maximum line length that IMAP sets, so POP3, NNTP and mailbox are unaffected. When a line exceeds the limit, or the buffer can't grow, ReadNextLine() returns an error, and IMAP closes the connection through its existing error path.
That also fixes a related problem: today, when GrowBuffer() fails or the 4 GB cap is reached, ReadNextLine() returns nullptr without setting *prv, so CreateNewLineFromSocket() keeps looping (while (!newLine && NS_SUCCEEDED(rv) ...)).
Magnus, is 64 MiB OK as the limit? Server response lines stay far below that (a SEARCH over a million messages is about 8 MB). Message body lines from FETCH literals go through the same buffer, though, so the limit has to leave room for broken messages with unwrapped base64.
Comment 3•10 days ago
•
|
||
Yeah 64MiB seems ok for a default limit. Perhaps make it a pref, something like mailnews.max_response_line_length?
| Assignee | ||
Comment 4•10 days ago
|
||
nsMsgLineStreamBuffer grew its buffer until a line end arrived, so a small COMPRESS=DEFLATE stream could expand into a line of gigabytes. IMAP now sets a limit from the new pref mailnews.max_response_line_length (64 MiB), and ReadNextLine() fails with NS_ERROR_ILLEGAL_INPUT beyond it, which closes the connection.
ReadNextLine() also reports a failure to grow the buffer instead of returning nullptr with success, which made CreateNewLineFromSocket() loop.
Signed-off-by: Olav Seyfarth <olav@seyfarth.de>
| Assignee | ||
Updated•10 days ago
|
Pushed by kaie@kuix.de:
https://hg.mozilla.org/comm-central/rev/09d0063ce6cd
Limit the length of IMAP response lines. r=mkmelin
Description
•