
CakePHP 5.4.2 - High - Remote - Cookie - Http Client cookie jar matches domains as a regex suffix
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · cakephp-cookie-suffix
Class: Cookie leak / plant Reach: Remote
CakePHP 5.4.2 (887b641) - Cake Software Foundation
CookieCollection::findMatchingCookies uses preg_match('/' . preg_quote($domain) . '$/', $host). That is a string suffix, not RFC 6265 domain-match. A cookie for api.partner.com is sent to evilapi.partner.com. A cookie for bank.com is sent to notbank.com.
Cookie::createFromHeaderString() also copies Set-Cookie Domain= with no check against the response host. addFromResponse from attacker.test with Domain=victim.internal stores that cookie and later attaches it to victim.internal.
An app that uses Cake\Http\Client with the default jar across more than one host can leak a partner session cookie to a suffix-confused sibling, or plant a cookie onto an internal host after fetching an attacker URL. other.com does not match. This is not a browser cookie bug. Stock cakephp/app does not call a second host by itself.
| ID | no CVE yet |
| Class | Cookie leak / plant (regex suffix domain match) |
| Reach | Remote (app uses Http Client jar across hosts) |
| CWE | CWE-565, CWE-201 |
| CVSS | High: 8.2 CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N |
| Product | CakePHP |
| Affected | 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) |
| Auth | app uses Cake\Http\Client with the default cookie jar across hosts |
| License | GNU Affero GPL v3.0 |
| Lab | 127.0.0.1 only |
Needs an application that keeps Cake\Http\Client cookies across more than one host (OAuth, webhooks, a user-supplied URL, a second API).
| Privilege | Method / sink | Lab-proven or inferred |
|---|---|---|
| Leak a stored cookie to a suffix-confused sibling | CookieCollection::addToRequest for https://evilapi.partner.com/ after a cookie with domain api.partner.com | Lab-proven. Request Cookie is sid=SECRET. RFC 6265 would not match |
| Same leak for a registrable suffix | Cookie domain bank.com, request host notbank.com | Lab-proven. Request Cookie is sid=SECRET |
| Negative control | Request host other.com | Lab-proven. No Cookie header |
| Plant a cookie for an internal host | addFromResponse of Set-Cookie: sid=x; Domain=victim.internal from https://attacker.test/ | Lab-proven. Stored domain is victim.internal; next request to that host sends sid=x |
| Session fixation / stolen partner session on the next Client call | Planted or leaked sid used as an API session | Inferred. Lab stops at the Cookie header oracle |
| Same-host send still works | Cookie domain api.partner.com to host api.partner.com | Lab-proven. Expected, not a bug |
Closed on this leftover: other.com does not match. Browser cookie jars are not this bug. No shell. Not unauthenticated RCE on a skeleton app.
I pinned cakephp/cakephp 5.4.2 after GHSA-2qh5, GHSA-fxf7, GHSA-vjqc, and the 5.4.2 filename= note. Http Client cookie matching is a regex suffix:
$pattern = '/' . preg_quote($domain, '/') . '$/';
if (!preg_match($pattern, $host)) {
continue;
}
addFromResponse passes the request host only as a default. A Domain= attribute from Set-Cookie overwrites it and is stored.
Wrong turns already recorded: treating this as a browser cookie bug; claiming other.com also matches; inflating a Cookie header oracle to ATO without an app that uses the jar across hosts. Theatre: a reverse shell.
python3 cakephp-cookie-suffix-Abraxas-Labs.py
or
cd lab
./run.sh
Git clone tag 5.4.2 (887b641de9f7aba06071f98f17edcbc573cbcf63) in PHP 8.3. Loopback oracle HTTP at 127.0.0.1:19420. No extra HTTP origin is required; the oracle runs CookieCollection from the pin.
sid=SECRET domain api.partner.com. addToRequest https://evilapi.partner.com/ -> Cookie: sid=SECRET.https://other.com/ -> no Cookie header.https://api.partner.com/ still sends sid=SECRET.bank.com -> https://notbank.com/ sends sid=SECRET.addFromResponse from https://attacker.test/ with Set-Cookie: sid=x; Domain=victim.internal; Path=/. Next https://victim.internal/ sends sid=x.SUCCESS cakephp-cookie-suffix suffix-leak=yes control-other=yes plant-domain=yes how=cakephp-5.4.2 CAKEPHP-COOKIE-SUFFIX-WITNESS
RFC 6265 domain-match (host === domain || str_ends_with($host, '.' . $domain)). Host-only cookies when Domain is omitted. Reject Domain that does not domain-match the request host. Reject public suffixes.
887b641de9f7aba06071f98f17edcbc573cbcf63)src/Http/Cookie/CookieCollection.php · src/Http/Cookie/Cookie.phpGNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.