How this check works
Scanaris reads the Set-Cookie headers your server sends when loading the home page and reviews the attributes of each cookie. It checks three things: that it carries Secure (only required if the site is served over HTTPS), that it carries HttpOnly and that it declares SameSite. If the cookie name suggests a session or authentication (session, auth, token, sid and similar), the finding is medium severity; otherwise low. There is one special case with its own medium severity: SameSite=None without Secure, which modern browsers reject outright, so the cookie does not work and it also reveals a configuration meant for cross-site use. Only the cookies sent in that first response are seen; the ones created after login are better checked with the command below or with the authenticated scan.
What each attribute means
- Secure: the cookie only travels over HTTPS. Without it, an HTTP request (an old link, a public network) sends it in the clear and anyone on the network reads it.
- HttpOnly: JavaScript cannot read it. It is the difference between an XSS stealing the session or not being able to.
- SameSite: when it is sent from another site.
Laxsends it on normal navigations but not on requests started by another website;Strictnever from outside;Nonealways, and requiresSecure. It is the main defence against CSRF.
What an attacker does with a session cookie missing these attributes
Without HttpOnly, any injected script reads document.cookie, sends the value to its server and logs in with your session. Without SameSite, a foreign page can submit a form to your site with the cookie attached and place an order or change an email on the user's behalf. Without Secure, it is enough for the user to open an http:// link to your domain on a shared network. In all three cases the result is the same: someone acts as your user.
How to fix it depending on your framework
// Express with express-session
app.use(session({
cookie: { secure: true, httpOnly: true, sameSite: 'lax' }
}));
// Next.js (Route Handler or Server Action)
cookies().set('session', value, { httpOnly: true, secure: true, sameSite: 'lax', path: '/' });
// Nuxt (server/api)
setCookie(event, 'session', value, { httpOnly: true, secure: true, sameSite: 'lax', path: '/' });
With Supabase in an app that has a server, the @supabase/ssr library stores the session in cookies with these attributes; in a pure SPA the session goes to localStorage, which is what the token in storage check measures. In Django, Rails or Laravel the attributes are configured in the session settings and come with sensible defaults; check that nobody lowered them to "fix" a development problem.
Check it is fixed
curl -sI https://yourdomain.com | grep -i "set-cookie"
curl -sI -X POST https://yourdomain.com/api/login -d "..." | grep -i "set-cookie"
Every session cookie should show Secure; HttpOnly; SameSite=Lax (or Strict). If your login is a form, look at the response in the browser tools, Network tab, response headers.
Frequently asked questions
My cookie is created by JavaScript (analytics, preferences). It cannot be HttpOnly.
Correct, and that is fine: those cookies give access to nothing. The check flags it at low severity for the missing attribute; what matters is that the session ones do have it.
I need SameSite=None because my app runs inside an iframe on another domain.
Then it is legitimate, always with Secure. Make sure the other CSRF defences (tokens in forms, Origin checks) are active, because SameSite no longer protects you.
Lax or Strict?
Lax for most cases: it keeps the session when the user arrives from an external link. Strict if the cookie gives access to something very sensitive and you accept that the user has to log in again when arriving from outside.