Fix out-of-bounds string reads on truncated compressed-RTF in the TNEF decoder - #10269
Merged
Conversation
…F decoder Co-Authored-By: Claude Fable 5 <[email protected]>
MiMoHo
force-pushed
the
held-tnef-rtf-oob
branch
from
July 16, 2026 08:14
54d79a8 to
5eae209
Compare
alecpl
pushed a commit
that referenced
this pull request
Jul 18, 2026
…F decoder (#10269) Co-authored-by: Claude Fable 5 <[email protected]>
alecpl
pushed a commit
that referenced
this pull request
Jul 18, 2026
…F decoder (#10269) Co-authored-by: Claude Fable 5 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
rcube_tnef_decoder::_decompressRTF()reads compressed-RTF input byte by byte withord($data[$in++]). On truncated or otherwise malformed compressed-RTF payloads the read index$incan advance past the end of the input within a single loop iteration, producing "Uninitialized string offset" PHP warnings (and reading out of bounds). The recent compressed-size sanity check (commit ed56e08) did not close this: the only input-exhaustion guard was placed at the bottom of the loop, so multipleord($data[$in++])reads in the back-reference branch — and the next iteration's flags read — could still run paststrlen($data).Root cause
program/lib/Roundcube/rcube_tnef_decoder.php, in_decompressRTF(): theif ($in >= $max_len) break;check sat at the end of thewhilebody (previously ~line 551). Within one iteration the code performs up to three separate reads (flags byte, then offset+length in the back-reference branch), and the trailing check does not prevent the next iteration'sord($data[$in++])flags read when$inhas already reached$max_len.Fix
Move the input-exhaustion check to the top of the loop and add a per-branch guard verifying that the required bytes remain before each read:
if ($in >= $max_len) break;(covers the flags read)if ($in + 1 >= $max_len) break;(needs two more bytes)if ($in >= $max_len) break;(needs one more byte)Decompression output for valid input is unchanged.
Testing
Added
TnefDecoderTest::test_decompressRTF_truncated, which feeds several truncated compressed-RTF payloads to_decompressRTF()with an error handler that promotes PHP warnings to exceptions. The test fails on current master ("Uninitialized string offset" at the flags read) and passes with the fix. The fulltests/Framework/TnefDecoderTest.phpsuite (5 tests, 51 assertions) passes, and phpstan (level 4) reports no new errors on the changed file.