GitHub Security Advisory: GHSA-g47v-rwmh-r9f8
Package: eml_parser (PIP)
Severity: MODERATE (CVSS 0.0)
CWE: CWE-674: Uncontrolled Recursion
Vulnerable versions: <= 3.0.0
Patched in: 3.0.1

Summary: eml_parser has recursion DoS via nested message/rfc822 attachments

Details:
### Summary

`EmlParser.get_raw_body_text()` recurses unconditionally for every nested `message/rfc822` attachment without any depth limit. An attacker who can supply a badly crafted EML file with approximately 120 nested `message/rfc822` parts triggers an unhandled `RecursionError` and aborts parsing of the message. A 12 KB EML file is enough to crash a worker.
Though this causes the parser to crash, it is an unlikely scenario as the suggested EML that crashes the parser would not pass basic RFC compliance tests.

### Details

The vulnerable function is `EmlParser.get_raw_body_text()` in `eml_parser/parser.py`. For every part of type `multipart/*`, the function iterates over its sub-parts; for every sub-part of type `message/rfc822`, it calls itself recursively on the inner message:

There is no depth parameter and no early-abort. CPython's default `sys.recursionlimit` is 1000. Each level of `message/rfc822` nesting adds approximately 8 frames to the stack (parser code + stdlib `_header_value_parser` calls), so roughly 120 nested levels exhaust the limit.

The `RecursionError` is not caught anywhere along the call chain, so it propagates out of `decode_email_bytes()` and aborts processing of the entire message.


### PoC

Environment: Python 3.12.3, eml_parser 3.0.0 (`pip install eml_parser==3.0.0`), default `sys.recursionlimit=1000`, Ubuntu 24.04 aarch64. No special configuration of `EmlParser`, default constructor.

Self-contained reproducer that builds the PoC and triggers the crash:

```python
import eml_parser

def build_poc(depth=124):
    inner = b"From: a@a\r\nTo: b@b\r\nContent-Type: text/plain\r\n\r\n.\r\n"
    msg = inner
    for i in range(depth):
        b = f"B{i}".encode()
        msg = (
            b'Content-Type: multipart/mixed; boundary="' + b + b'"\r\n\r\n'
            b'--' + b + b'\r\nContent-Type: message/rfc822\r\n\r\n'
        ) + msg + b'\r\n--' + b + b'--\r\n'
    return msg

ep = eml_parser.EmlParser()
ep.decode_email_bytes(build_poc())
# RecursionError after ~76 ms on Apple Silicon (Ubuntu 24.04 aarch64).
```

Note that the suggested code does not produce an RFC compliant message.
Resulting EML payload size: 12,369 bytes.
SHA-256 of generated PoC: `00f15f635e21b4144967c2893b37425e6a6bd7b4185c557e5c7e904e1e6d18e8`

The crash is deterministic on a stock install. No network, no special headers, no large attachments.

### Impact

Denial of service of any pipeline that processes attacker-supplied EML files using `eml_parser`.

A single 12 KB email is enough to crash a worker. If the worker is a long-running process triaging multiple emails, the unhandled exception aborts processing of the whole batch unless the caller wraps the call in a broad `try/except`. Even then, attacker-supplied volume can keep workers in a perpetual restart loop.

The vulnerability is exploitable pre-authentication in any deployment that ingests emails from external senders which have not been subject to any kind of basic validation.
Considering