Skip to content

Limit MIME nesting depth to prevent unbounded recursion#59

Open
iliaal wants to merge 1 commit into
php:masterfrom
iliaal:fix/limit-mime-nesting-depth
Open

Limit MIME nesting depth to prevent unbounded recursion#59
iliaal wants to merge 1 commit into
php:masterfrom
iliaal:fix/limit-mime-nesting-depth

Conversation

@iliaal
Copy link
Copy Markdown

@iliaal iliaal commented Jun 7, 2026

mailparse never enforced a limit on MIME nesting depth. MAXLEVELS (20) has been defined but never referenced; the only structural check is MAXPARTS, which counts a single part's children and so never trips for a chain that nests one child per level. A message built from repeated "Content-Type: message/rfc822" parts, or singly-nested multipart containers, produces an arbitrarily deep tree. php_mimepart_enum_parts() walks that tree recursively, so mailparse_msg_get_structure(), mailparse_msg_get_part() and the extract paths overflow the C stack and crash. This enforces MAXLEVELS in alloc_new_child_part() and fails the parse once the limit is reached, the same way MAXPARTS is already handled.

Reproducer: mailparse_msg_get_structure() on a message of ~100k repeated "Content-Type: message/rfc822\n\n" parts segfaults before the fix.

A message that nests one child part per level (e.g. repeated
"Content-Type: message/rfc822" parts, or singly-nested multipart
containers) was bounded only by MAXPARTS, which counts children per
part and never trips for a one-child-per-level chain. Parse depth was
therefore attacker-controlled and unbounded.

php_mimepart_enum_parts() / enum_parts_recurse() walk the tree
recursively, so a deep enough message overflowed the C stack (SIGSEGV)
on mailparse_msg_get_structure(), mailparse_msg_get_part() and the
extract paths. The descent in php_mimepart_process_line() also made
parsing such a message quadratic.

Enforce the existing (previously unused) MAXLEVELS cap in
alloc_new_child_part(): refuse to create a child past the limit and
fail the parse, matching the existing MAXPARTS handling.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant