
CakePHP 5.4.2 - High - Remote - CRLF - attachment Content-Type and Content-ID leftover
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-attachment-crlf
Class: MIME-part header injection Reach: Remote
CakePHP 5.4.2 (887b641) - Cake Software Foundation
5.4.2 already strips ", \r, and \n from multipart name= / filename= (FormDataPart::_headerParameterToString). That is the control. Content-Type and Content-ID were left as raw concatenation. Message::setAttachments copies an UploadedFile client media type into that type field with no extra filter.
An app that attaches a user upload, or that passes a user contentId, puts those bytes on the MIME part. getBodyString() then shows a second header line under that part.
| ID | no CVE yet |
| Class | MIME-part header injection |
| Reach | Remote (app that attaches a user upload or a user contentId) |
| CWE | CWE-93 |
| CVSS | Medium: 5.4 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N |
| Product | CakePHP |
| Affected | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Auth | application that attaches a user upload (UploadedFile client MIME) or a user contentId |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
Someone who can influence attachment metadata the app passes into Message::setAttachments / addAttachment can inject MIME-part headers.
| Privilege | Method / sink | Kind | Lab-proven or inferred |
|---|---|---|---|
Extra Content-Type header line | setAttachments with 'mimetype' => "text/plain\\r\\nX-Injected: …" | Integrity of MIME part headers | Lab-proven. Witness line present |
Extra Content-ID header line | 'contentId' => "cid@…>\\r\\nX-Injected: …" (inline part) | Integrity of MIME part headers | Lab-proven. Witness line present |
| Same injection via upload MIME | UploadedFile::getClientMediaType() copied onto mimetype | Integrity of MIME part headers | Lab-proven. Witness line present |
filename= CRLF | attachment name with CR/LF | Closed | Lab-proven closed. 5.4.2 strip holds |
Envelope RCPT / Bcc via this sink | MIME part headers in the body | Closed | That is SmtpTransport pair-only strip, a sibling |
| SMTP send | lab calls getBodyString() only | Closed | No transport, no shell |
Inferred from the same concat, not demonstrated: a crafted type or contentId that includes a multipart boundary could split the message into extra parts in a receiving MUA. I did not send mail.
Same pin leftovers: window SQLi, collate SQLi, cache unserialize.
I pinned cakephp/cakephp 5.4.2 after the bakery note that multipart Content-Disposition filename= injection was fixed. _headerParameterToString is the sanitizer:
$transliterated = Text::transliterate(str_replace(['"', "\r", "\n"], '', $value));
__toString() still does:
if ($this->type) {
$out .= 'Content-Type: ' . $this->type . "\r\n";
}
if ($this->contentId) {
$out .= 'Content-ID: <' . $this->contentId . ">\r\n";
}
Message::setAttachments copies the upload client type with no strip. attachFiles / attachInlineFiles then call $part->type($fileInfo['mimetype']) and $part->contentId($fileInfo['contentId']).
Wrong turns already recorded: treating envelope RCPT as this leftover (the extra line is in the body); claiming filename= still injects (it does not); sending SMTP; a reverse shell. Theatre.
python3 cakephp-attachment-crlf-Abraxas-Labs.py
or
cd lab
./run.sh
Target only http://127.0.0.1:19460. PHP 8.3, CakePHP tag 5.4.2 cloned at build. lab_server.php exposes Message::setAttachments. Four cases: filename control, mimetype, contentId, UploadedFile media type.
SUCCESS cakephp-attachment-crlf how=live pin=5.4.2 sha=887b641de9f7aba06071f98f17edcbc573cbcf63 mimetype=yes contentId=yes upload=yes filename-stripped=yes CAKEPHP-ATTACHMENT-CRLF-WITNESS
Run type, contentId, and transferEncoding through the same " / \r / \n strip as _headerParameterToString. Reject the value if it still contains a line break after strip. Cover UploadedFile client MIME and explicit mimetype / contentId in the mailer tests, not only filename=.
887b641de9f7aba06071f98f17edcbc573cbcf63)FormDataPart.php · Message.phpfilename= stripGNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.