Summary
lws_parse_set_cookie() in lib/roles/http/cookie.c overwrites the
already-parsed cookie name and/or value with the literal string
"T" whenever the Set-Cookie header contains the HttpOnly and/or
Secure attributes. This is not cosmetic: the corrupted name/value is
what gets persisted to the NSC cookie jar and re-sent on subsequent
requests, so any cookie using these (extremely common) attributes is
effectively unusable.
Root cause
lws_parse_set_cookie() (lib/roles/http/cookie.c) uses a single loop
variable n to index into two arrays with different, incompatible
orderings:
cft[] — a lookup table used only to identify which cookie
attribute matched a given ; xxx fragment:
static struct {
const char *const name;
uint8_t len;
} cft[] = {
{ "domain=", 7 }, // n == 0
{ "path=", 5 }, // n == 1
{ "expires=", 8 }, // n == 2
{ "max-age=", 8 }, // n == 3
{ "httponly", 8 }, // n == 4
{ "secure", 6 }, // n == 5
};
enum lws_cookie_elements — the indices used for c.f[] / c.l[]
in struct lws_cookie:
enum lws_cookie_elements {
CE_DOMAIN, // 0
CE_PATH, // 1
CE_EXPIRES, // 2
CE_MAXAGE, // 3
CE_NAME, // 4 <-- collides with cft[4] == "httponly"
CE_VALUE, // 5 <-- collides with cft[5] == "secure"
CE_HOSTONLY, // 6
CE_SECURE, // 7
CE_COUNT
};
In the attribute-matching branch:
if (n == 4 || n == 5) {
c.f[n] = "T";
c.l[n] = 1;
break;
}
When the httponly attribute matches (n == 4), this writes into
c.f[4], which per lws_cookie_elements is CE_NAME — clobbering the
name that was already parsed earlier in the same loop. When secure
matches (n == 5), it writes into c.f[5], i.e. CE_VALUE. The
intended targets, CE_HOSTONLY (6) and CE_SECURE (7), are never
touched by this branch at all.
Effect
Set-Cookie attributes present |
Result |
| none |
name/value correct |
SameSite=... only (not in cft[]) |
name/value correct |
HttpOnly |
name replaced with "T" |
Secure |
value replaced with "T" |
Secure; HttpOnly (the common case for real session cookies) |
both name and value replaced with "T" |
The resulting garbage line does get written all the way through to the
NSC file via lws_cookie_write_nsc(), e.g.:
Summary
lws_parse_set_cookie()inlib/roles/http/cookie.coverwrites thealready-parsed cookie name and/or value with the literal string
"T"whenever theSet-Cookieheader contains theHttpOnlyand/orSecureattributes. This is not cosmetic: the corrupted name/value iswhat gets persisted to the NSC cookie jar and re-sent on subsequent
requests, so any cookie using these (extremely common) attributes is
effectively unusable.
Root cause
lws_parse_set_cookie()(lib/roles/http/cookie.c) uses a single loopvariable
nto index into two arrays with different, incompatibleorderings:
cft[]— a lookup table used only to identify which cookieattribute matched a given
; xxxfragment:enum lws_cookie_elements— the indices used forc.f[]/c.l[]in
struct lws_cookie:In the attribute-matching branch:
When the
httponlyattribute matches (n == 4), this writes intoc.f[4], which perlws_cookie_elementsisCE_NAME— clobbering thename that was already parsed earlier in the same loop. When
securematches (
n == 5), it writes intoc.f[5], i.e.CE_VALUE. Theintended targets,
CE_HOSTONLY(6) andCE_SECURE(7), are nevertouched by this branch at all.
Effect
Set-Cookieattributes presentSameSite=...only (not incft[])HttpOnly"T"Secure"T"Secure; HttpOnly(the common case for real session cookies)"T"The resulting garbage line does get written all the way through to the
NSC file via
lws_cookie_write_nsc(), e.g.: