squirrelscan
GitHub

Cookie flags: Secure, HttpOnly and SameSite on Set-Cookie

SameSite=None without Secure is rejected outright, and a session cookie without HttpOnly is readable by any script. squirrel parses every Set-Cookie.

Set-Cookie carries attributes that decide where a cookie may travel and who may read it. Secure stops the cookie being sent over plain HTTP. HttpOnly stops client-side JavaScript reading it, which closes the usual path from a cross-site scripting bug to a stolen session. SameSite decides whether the cookie rides along on requests started by other sites.

Browsers now default an absent SameSite to Lax, so omitting it is weaker documentation rather than an open door. SameSite=None is the exception: it re-enables cross-site sending for cases like an embedded widget, and browsers reject the cookie entirely unless Secure is set alongside it.

What squirrel checks

The rule reads the set-cookie response header of each crawled page, splits it into individual cookies, and emits these checks:

  • cookie-flags passes when the page sets no cookies at all. Message: No cookies set on this page.
  • cookie-samesite-none-insecure fails when a cookie declares SameSite=None without Secure. Message: 1 cookie(s) set SameSite=None without Secure — modern browsers reject this combination, with the cookie names listed.
  • cookie-secure warns when a cookie on an HTTPS page has no Secure attribute. Message: 2 cookie(s) missing the Secure flag. The check is skipped on HTTP pages, where there is no secure connection to pin the cookie to.
  • cookie-httponly warns when a cookie has no HttpOnly attribute. Message: 2 cookie(s) missing the HttpOnly flag.
  • cookie-samesite reports info when a cookie declares no SameSite, or declares it with an empty value such as SameSite=. Message: 2 cookie(s) don't explicitly declare SameSite (browsers default to Lax).
  • cookie-flags passes when cookies were set and none of the above fired. Message: 3 cookie(s) set with Secure, HttpOnly, and SameSite configured correctly.

Multiple cookies in one header value are split on newlines and on commas that are followed by a name= pair, so an Expires date containing a comma does not split a cookie in two. Only cookies your server sets in a response header are seen; cookies written by JavaScript are not.

How to fix it

Set-Cookie: session=abc123; Path=/; Secure; HttpOnly; SameSite=Lax

Set the flags where the cookie is created, in the session middleware or the framework’s cookie helper. Drop HttpOnly only for a cookie your own frontend genuinely reads, such as a CSRF token mirrored into the DOM. When you need SameSite=None, add Secure in the same change.

Only cookies your server sets in a Set-Cookie response header are inspected. A cookie written by JavaScript, whether yours or a third party’s, never reaches this rule.

Rule IDsecurity/cookie-flags
CategorySecurity
ScopePer-page
Severitywarning
Weight5/10

Enable / disable

Disable this rule

[rules]
disable = ["security/cookie-flags"]

Disable all Security rules

[rules]
disable = ["security/*"]

Enable only this rule

[rules]
enable = ["security/cookie-flags"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Security findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Security section of the report. Every cookie missing a flag is listed by name and page. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close