Skill v1.0.0
currentLLM-judged scan90/100version: "1.0.0" name: auth-and-web-security description: >- Non-obvious auth/security gaps: JWT verification shortcuts, insecure token storage, missing CSRF protection, and non-constant-time secret comparison. Use when writing authentication, session/token handling, or any endpoint that compares a secret/password/API key. Not a substitute for a full security review — see security-review for that.
Auth & Web Security
JWT verification shortcuts
Wrong: Decoding a JWT and trusting its claims without restricting which algorithm is acceptable, or without checking exp/aud/iss.
Right: Explicitly pin the expected algorithm(s) when verifying (never let the token's own alg header decide), and check expiry, audience, and issuer against expected values — most JWT libraries do this if you pass the right options, but don't assume the defaults cover it.
Why: A library that lets the token specify its own algorithm can be tricked into verifying with alg: none or a different algorithm than the server intended (e.g. an RS256-signed token re-submitted as HS256, verified against the public key as if it were an HMAC secret) — accepting an unverified or wrongly-verified token means an attacker can forge one. Skipping exp means a stolen token never expires.
Token storage: localStorage vs httpOnly cookies
Wrong: Storing an access/session token in localStorage or a non-httpOnly cookie so client JS can read it.
Right: Store session tokens in an httpOnly, secure, sameSite cookie that JS can't read at all.
Why: Anything readable by your own JS is readable by any injected script (a dependency's supply-chain compromise, a reflected XSS bug elsewhere on the page) — localStorage has no protection against this. An httpOnly cookie is never exposed to JS at all, so an XSS bug elsewhere can't exfiltrate the session even if it can run arbitrary script.
CSRF exposure with cookie-based auth
Wrong: State-changing endpoints (POST/PUT/DELETE) that rely solely on a cookie for auth, with no CSRF token and no sameSite restriction on the cookie.
Right: Set sameSite=Lax or Strict on the auth cookie, and for anything that needs cross-site form submission, require a CSRF token validated server-side in addition to the cookie.
Why: Cookies are sent automatically by the browser on any request to the domain, including ones triggered by a malicious page the user happens to have open — if the server only checks "is there a valid cookie," it can't distinguish a request the user intended from one a different site silently triggered on their behalf.
Constant-time comparison for secrets
Wrong: if (providedApiKey === storedApiKey) or similar ==/=== comparison for API keys, tokens, or password hashes.
Right: Use a constant-time comparison (crypto.timingSafeEqual or the equivalent in your language/framework) for any secret comparison.
Why: === short-circuits at the first mismatched character, so the time it takes to return false leaks how many leading characters were correct — with enough requests, an attacker can reconstruct the secret one character at a time from timing alone. This is the same issue as the webhook-signature entry in resilient-integrations, but applies just as much to login and API-key checks.