v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
MEDIUM AI PREVALENCE: MEDIUM auth.cookie.samesite-none-insecure

A cookie is being set with SameSite=None but WITHOUT Secure.

Why AI tools produce this: AI coding tools produce this regularly, typically when prompted for a shortcut or a quick fix.

Why this matters

SameSite=None requires Secure: modern browsers reject a SameSite=None cookie that is not also Secure, so the cookie is silently dropped. Worse, if anything does accept it, the cookie is a cross-site cookie travelling over plaintext. It can be sent over plain HTTP and offers no CSRF protection at all.

Fix: add secure: true, and only use SameSite=None when you genuinely need the cookie sent on cross-site requests; otherwise prefer SameSite=Strict or Lax. See CWE-1275.

VULNERABLE
vulnerable.ts
import type { Response } from 'express';

export function loginBad(res: Response, v: string) {
  // ruleid: auth.cookie.samesite-none-insecure
  res.cookie('sid', v, { httpOnly: true, sameSite: 'none' });
}

export function loginBad2(res: Response, v: string) {
  // ruleid: auth.cookie.samesite-none-insecure
  res.cookie('sid', v, { httpOnly: true, sameSite: 'None', secure: false });
}

export function loginBad3(res: Response, v: string) {
  // ruleid: auth.cookie.samesite-none-insecure
  const opts = { sameSite: 'none', path: '/' };
  res.cookie('sid', v, opts);
}

export function setCookieHeader(res: Response, v: string) {
  // ruleid: auth.cookie.samesite-none-insecure
  res.setHeader('Set-Cookie', `sid=${v}; HttpOnly; SameSite=None`);
}
SAFE
safe.ts
import type { Response } from 'express';

// ok: auth.cookie.samesite-none-insecure -- None is valid WITH Secure
export function crossSiteGood(res: Response, v: string) {
  res.cookie('sid', v, { httpOnly: true, sameSite: 'none', secure: true });
}

// ok: auth.cookie.samesite-none-insecure -- None (capitalised) WITH Secure
export function crossSiteGood2(res: Response, v: string) {
  res.cookie('sid', v, { httpOnly: true, sameSite: 'None', secure: true });
}

// ok: auth.cookie.samesite-none-insecure -- Lax never requires Secure here
export function laxCookie(res: Response, v: string) {
  res.cookie('sid', v, { httpOnly: true, sameSite: 'lax' });
}

// ok: auth.cookie.samesite-none-insecure -- Strict WITH Secure
export function strictCookie(res: Response, v: string) {
  res.cookie('sid', v, { httpOnly: true, sameSite: 'strict', secure: true });
}

// ok: auth.cookie.samesite-none-insecure -- Set-Cookie header with None AND Secure
export function setCookieHeaderGood(res: Response, v: string) {
  res.setHeader('Set-Cookie', `sid=${v}; HttpOnly; SameSite=None; Secure`);
}

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

// oauthlint-disable-next-line auth.cookie.samesite-none-insecure -- <reason>

References

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#samesitenone_requires_secure ↗https://cwe.mitre.org/data/definitions/1275.html ↗