Website problems
Cookies without the Secure attribute
The `Secure` attribute tells a browser to send a cookie only over HTTPS. Without it, the cookie is attached to any request to the domain, including a plain HTTP one — and a single such request, triggered by a mistyped address, an old bookmark or an injected image, is enough for anyone on the network path to read it. When the cookie is a session identifier, reading it is equivalent to being logged in as that user.
Why serving the site over HTTPS is not enough
A cookie's attributes travel with the cookie, not with the page that set it. A cookie set over HTTPS without `Secure` is still sent on a later HTTP request to the same domain.
Those requests happen. Someone types the bare domain, follows a link from an old email, or loads a page that references an HTTP resource on your host.
An HTTP-to-HTTPS redirect does not help: the request carrying the cookie has already been sent by the time the redirect is received.
HSTS does help, for browsers that have received the header — they upgrade internally and never send the plain request. It does not cover the first visit before the header arrives, or anything that is not a browser.
So `Secure` is the attribute that closes the gap the redirect cannot, and it costs nothing on a site that already serves HTTPS.
The three attributes that go together
`Secure`: HTTPS only. Prevents the cookie crossing the network in clear text.
`HttpOnly`: not readable by JavaScript. Prevents a script — including an injected one — from reading the cookie through `document.cookie`. Every session cookie should have it; a cookie the front-end genuinely needs to read cannot.
`SameSite`: controls whether the cookie is sent on cross-site requests, which is the cross-site request forgery defence.
They address three different attacks: network interception, script access, and cross-site submission. A session cookie needs all three, and having one does not substitute for another.
`__Secure-` and `__Host-` name prefixes let the browser enforce the attributes: a cookie named `__Host-session` is rejected unless it is `Secure`, path `/`, and has no `Domain` attribute. That turns a convention into a guarantee.
Where the attribute goes missing
Framework defaults set before HTTPS was universal, carried forward through upgrades.
Cookies set by application code rather than by the session middleware, where the developer writing that line did not repeat the attributes.
Third-party scripts setting their own cookies on your domain, which you do not control and can only audit.
Development configuration promoted to production, where `Secure` was disabled so the cookie would work over plain HTTP locally.
Load balancers and proxies that rewrite cookies, and occasionally strip attributes while doing it.
How to check it yourself
`curl -I https://example.com | grep -i set-cookie` shows the cookies set on that response with their attributes.
In the browser, the Application panel lists every cookie with columns for `Secure`, `HttpOnly` and `SameSite`, which is the fastest complete view.
Check after logging in, not only on the home page. The session cookie is the one that matters and it is set at authentication.
In the console, `document.cookie` returns everything readable by JavaScript. Anything in that list is not `HttpOnly`, and a session identifier appearing there is the finding.
How to fix it
Set `Secure` on every cookie. There is no cost on an HTTPS site and no reason to omit it.
Set `HttpOnly` on every cookie the front-end does not read. Audit that list rather than assuming: most cookies believed to be read by scripts are not.
Use the `__Host-` prefix for session cookies so the browser enforces the attributes rather than trusting the server to send them.
Configure it in the session middleware, not per call site, so a new cookie inherits the policy instead of needing it remembered.
For local development, use a locally trusted certificate rather than disabling `Secure`. That removes the configuration difference that ships to production.
How VeriFixScan detects it
`cookies.secure` reads the cookies set on the crawled pages and reports the ones without the `Secure` attribute, with the cookie name and the page that set it.
`cookies.httponly` and `cookies.samesite` report the other two attributes, and `cookies.sensitive` flags cookies whose names suggest they carry a session or authentication token.
`cookies.inventory` lists every cookie observed with its full attribute set, which is what turns individual findings into a policy decision.
The scan is anonymous, so cookies set only after authentication are outside it — the report covers what an unauthenticated visitor receives.
Frequently asked questions
- My site is HTTPS only. Do I still need Secure?
- Yes. The attribute travels with the cookie, not with the page that set it, so without it the cookie is attached to any plain HTTP request to the domain — and the redirect that follows arrives too late.
- What is the difference between Secure and HttpOnly?
- Secure controls the transport: HTTPS only. HttpOnly controls script access: JavaScript cannot read it. They defend against network interception and script access respectively, and a session cookie needs both.
- What does the __Host- prefix do?
- It makes the browser enforce the attributes. A cookie named with that prefix is rejected unless it is Secure, has path /, and carries no Domain attribute — so the policy cannot be silently dropped.
Sources
Related
VeriFixScan crawls a site and applies its checks to every page it reaches, keeping the evidence behind each finding. Scanning one website is free.
Scan a website