Secure, HttpOnly and SameSite each close a different attack path - but severity is set by the chain the missing flag enables, not by the absence alone.
A Set-Cookie header without the Secure flag sends a session token over an unencrypted connection. Without HttpOnly, any script on the page can read it. Without SameSite, a cross-origin form forces the browser to include it in a forged request. Each missing attribute is a deterministically readable fact - but the severity depends on the chain the absence enables, not on the absence alone.
Secure, HttpOnly and SameSite each close a different attack path at the transport, script and cross-origin layer respectively. A cookie can be missing all three, one, or none - and the risk profile changes at each combination. Checking header presence is the first step; confirming the chain that the missing flag opens is what decides the severity number.
Reading the Set-Cookie header tells you which flags are absent. Confirming the chain requires a second probe for each class. For Secure, the confirming artifact is the cookie appearing in a request sent over HTTP - observable when the application runs a mixed-content flow or has an HTTP endpoint that redirects to HTTPS after the cookie is already in-flight. For HttpOnly, the confirming step is an XSS-class reflection: if a script-execution sink is confirmed on any page that shares the cookie scope, the cookie is confirmed exfiltrable. SameSite absence is confirmed by a cross-origin POST that the server accepts with the session cookie forwarded - the same differential as the CSRF confirmation path.
# Example A - three flags missing on a session cookie HTTP/1.1 200 OK Set-Cookie: session=abc123; Path=/ # no Secure, no HttpOnly, no SameSite # Example B - same endpoint, all flags present HTTP/1.1 200 OK Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/ # Example C - common mismatch: Secure and SameSite present, # HttpOnly omitted - JS access still open HTTP/1.1 200 OK Set-Cookie: session=abc123; Secure; SameSite=Strict; Path=/
The probe is read-only: no write to any data store, no script execution triggered during header inspection. The confirming step for HttpOnly requires a live XSS sink be established first - the cookie-flag finding and the XSS finding are separate records that correlate into a combined severity when both are confirmed.
A missing flag alone is a medium. A missing flag plus a confirmed sink that reaches it is high or critical, depending on the sink. The table below tracks how severity shifts as the chain deepens - confirming only the header state without the chain is accurate but incomplete, and the risk score reflects what is actually proven.
| Missing flag | Alone | + confirmed chain | What decides the chain |
|---|---|---|---|
| Secure | Medium - cookie sent over HTTP | High - session observed on a plaintext exchange | HTTP endpoint or mixed-content resource in the same scope |
| HttpOnly | Medium - JS read access open | Critical - confirmed cookie exfil via XSS execution sink | Stored or reflected XSS confirmed on any in-scope page |
| SameSite absent | Medium - cross-origin carriage open | High - state-change accepted from a controlled origin (CSRF) | State-changing endpoint without a validated CSRF token |
| All three absent | High - compound exposure | Critical - any of the three chains can confirm | First confirmed chain anchors the severity |
Correlating the cookie flag finding with an XSS or CSRF finding is what justifies the severity escalation. Raising the combined finding as a single unit of work - with both confirming artifacts attached - gives the remediation team the full picture rather than two medium findings that look independent on a dashboard.
The Secure, HttpOnly and SameSite flags describe the access policy. The Domain, Path and Max-Age attributes describe who gets the cookie and how long it lives. An HttpOnly absence on a cookie scoped to a single path is a different finding from one scoped to the root domain - the second version hands the same token to every page and subdomain. When Domain is set to the registered domain (.example.com) rather than the specific host (app.example.com), any subdomain - including one that may have different trust properties or a looser CSP - receives the same session token. A persistent Max-Age in the tens of millions means a stolen token works long after the user thinks they have logged out.
# Narrowest scope: current host, path-restricted, session-only Set-Cookie: session=TOKEN; Secure; HttpOnly; SameSite=Strict; Path=/app # Broad scope: all subdomains, root path, persistent for ~1 year Set-Cookie: session=TOKEN; Secure; HttpOnly; SameSite=Lax; Domain=.example.com; Path=/; Max-Age=31536000 # Any subdomain - including a less-hardened one - receives this token # Worst case: broad domain, no flags, persistent Set-Cookie: session=TOKEN; Domain=.example.com; Path=/; Max-Age=31536000 # No Secure, no HttpOnly, no SameSite - sent over HTTP to all subdomains, JS-readable, # cross-origin carriable, and the window is a year wide
The finding records all four dimensions: the flags present and absent, the Domain and Path scope, the persistence duration, and the confirmed chain that the combination enables. Fixing only the flags while leaving an overly broad Domain is an incomplete remediation; the posture reflects that until all four are correct.
The cookie-attribute check is one of the few findings where the header inspection alone is deterministic and the confirming chain is the work that follows - not a reason to skip the inspection, but a reason to keep severity calibrated to what is actually proven rather than what the worst-case chain could eventually reach.