curl · Report #3971551
20: HTAB before `Secure` attribute silently drops the Secure cookie flag
How it was found
Summary
A Set-Cookie header using HTAB (horizontal tab) instead of SPACE before the Secure attribute — e.g. Set-Cookie: sid=SECRET;\tSecure — causes curl to store the cookie without its Secure flag. The cookie is then sent over plaintext HTTP on subsequent requests to the same host.
The space-separated form Set-Cookie: sid=SECRET; Secure works correctly.
Affected versions
curl 8.13.0 through at least 8.21.0 (all versions containing commit 1aea05a6c26, "cookie: convert to using strparse", 2025-02-18).
Root cause
In lib/cookie.c, parse_cookie_header() uses a do/while loop that parses each cookie attribute:
do {
if(!curlx_str_cspn(&ptr, &name, ";\t\r\n=")) {
// parse attribute
}
} while(!curlx_str_single(&ptr, ';'));
After consuming the ; separator, ptr points at the HTAB. Since \t is in the reject set of curlx_str_cspn, the function sees it as the first character, returns an empty match (failure), and the if block is skipped. Then curlx_str_single(&ptr, ';') fails because the current byte is \t, not ;, so the loop exits. The Secure attribute is never parsed, but the cookie is still stored.
The previous parser (before 1aea05a6c26) had while(ISBLANK(*ptr)) ptr++; before parsing each attribute, which correctly skipped HTAB. This blank-skipping was lost in the strparse conversion. The helper curlx_str_passblanks() exists in the codebase but is not called here.
Reproduction
Expected vs actual output
Expected: Neither cookie is sent over HTTP (both have Secure).
Actual:
HTAB HTTP follow-up: sid=HTAB_SECRET <-- leaked over HTTP
SPACE HTTP follow-up: <none> <-- correctly withheld
HTAB jar secure flag: FALSE <-- wrong
SPACE jar secure flag: TRUE <-- correct
Impact
The Secure flag is a confidentiality boundary that prevents cookies from being sent over unencrypted connections. Silently dropping it means a session cookie intended to be HTTPS-only is exposed on any subsequent HTTP request to the same host. A network attacker observing that HTTP traffic can capture the cookie. All attributes at or after the HTAB position are similarly skipped (e.g. HttpOnly).
HTAB is valid optional whitespace per both RFC 6265 section 5.2 and the HTTP grammar (OWS). The old parser handled it correctly.