← Back to the library
SecurityApplied · 7 min

Another site can make signed-in users perform actions

“A page on another domain submits a form or fires a request to the app, the browser attaches the session cookie, and the state change succeeds as if the user had clicked it.”

THE PRINCIPLE

Ambient credentials need proof of intent. SameSite narrows when cookies are sent; it does not replace a server-side CSRF check.

FIRST MOVES

  1. Make sure no state change is reachable by GET; SameSite=Lax still sends cookies on cross-site top-level GET navigations.
  2. On POST/PUT/PATCH/DELETE, reject Sec-Fetch-Site values other than same-origin (or explicitly trusted same-site callers).
  3. When Fetch Metadata is absent, require an exact Origin match; a missing Origin or Origin: null is not proof of same origin.
  4. For apps that need tokens, use a synchronizer token or an HMAC-signed double-submit cookie bound to the session.
  5. Set session cookies with __Host-, Secure, HttpOnly, and SameSite=Lax or Strict. Remember sibling subdomains count as same-site.

TOOLS: THEN → NOW

SameSite=Lax as the whole defenseSameSite as defense in depth, plus Fetch Metadata or CSRF tokens
Naive double-submit cookieSynchronizer token or HMAC-signed, session-bound double-submit
Referer substring checksSec-Fetch-Site with an exact Origin allowlist fallback

PATTERN SNAPSHOT

const UNSAFE = new Set(["POST", "PUT", "PATCH", "DELETE"]);
const TRUSTED_ORIGINS = new Set(["https://app.example.com"]);
const forbidden = () => new Response("Forbidden", { status: 403 });

export function csrfGuard(req: Request): Response | null {
  if (!UNSAFE.has(req.method)) return null;
  const site = req.headers.get("sec-fetch-site");
  if (site) return site === "same-origin" ? null : forbidden();
  // Fallback for clients that omit Fetch Metadata: exact Origin match only.
  const origin = req.headers.get("origin");
  return origin && TRUSTED_ORIGINS.has(origin) ? null : forbidden();
}

CLOSE THE AI. EXPLAIN THIS.

An endpoint changes the account email on GET /settings?email=… and the session cookie is SameSite=Lax. Can another site trigger it, and why?

HOW IT WORKS UNDERNEATH

SOURCES

Guide reviewed