All 28 checks with why-it-matters prose, severity, and cross-references to related audits.
Session cookies without the Secure, HttpOnly, and SameSite flags are the most common entry point for session hijacking. Dropping HttpOnly makes the cookie readable by any JavaScript on your page — a single XSS flaw anywhere on the domain hands an attacker every active session. Dropping Secure lets the cookie travel over unencrypted HTTP connections, where network attackers can intercept it. Missing SameSite exposes the session to CSRF attacks. Together these flags implement the three-sided defense OWASP A07 (Identification & Authentication Failures) and NIST 800-63B expect as a baseline for any session credential.
Why this severity: High because missing any one of these three flags creates a direct, exploitable path to session token theft and full account takeover.
saas-authentication.session-management.session-tokens-secureSee full patternA session with no expiry or a 90-day timeout hands attackers an indefinitely valid credential from a single stolen cookie. NIST 800-63B §7.2 and PCI-DSS Req-8.2.8 both require session termination after a defined inactivity period — for good reason. A user who forgets to log out on a shared machine, or whose cookie is skimmed from an insecure connection, can have their account accessed for weeks or months with no recourse. OWASP A07 specifically lists insufficient session expiration as an authentication failure vector.
Why this severity: High because a non-expiring or excessively long-lived session token gives an attacker durable account access that persists long after the original compromise.
saas-authentication.session-management.session-expirySee full patternA refresh token that never rotates is a long-lived credential equivalent: steal it once, impersonate the user indefinitely. Token refresh without rotation means CWE-613 (Insufficient Session Expiration) applies in practice even when session expiry is configured correctly — the refresh token keeps re-issuing access tokens forever. NIST 800-63B §7.1 (Session Bindings) requires that bound authenticators be invalidated when the session ends, and RFC 9700 (OAuth 2.0 Security Best Current Practice, January 2025) requires refresh tokens for public clients to be sender-constrained or use rotation with reuse detection. OWASP A07 (Identification and Authentication Failures) lists perpetual credentials as a named failure mode.
Why this severity: High because a static refresh token captured once provides perpetual account access that bypasses access token expiry entirely.
saas-authentication.session-management.refresh-token-rotationSee full patternWhen a user changes their password they are often responding to a suspected compromise. Failing to invalidate existing sessions at that moment means an attacker who already has a session token retains access even after the user takes corrective action. CWE-613 and CWE-287 both cover this failure mode, and OWASP ASVS V3.3.1 requires that sessions be terminated on credential change. OWASP A07 lists this as an authentication lifecycle gap. In short: a password change that does not invalidate sessions is not a password change — it is a password addition.
Why this severity: Medium because exploitation requires an attacker to already possess a valid session token, but that prior access makes this a critical path in incident recovery.
saas-authentication.session-management.session-invalidation-password-changeSee full patternSession fixation (CWE-384, CAPEC-61) lets an attacker plant a known session token in a victim's browser before login, then use that same token after the victim authenticates. The attacker never needs to steal anything — they supplied the token themselves. This attack predates modern auth libraries and is largely invisible in code review because the vulnerability is an absence: the session is never regenerated after login. OWASP A07 (Identification and Authentication Failures) lists session fixation as a named failure mode, and the OWASP ASVS Session Management chapter requires that session identifiers be regenerated on authentication.
Why this severity: High because a successful session fixation attack gives the attacker an authenticated session for any user they can trick into logging in, with no stolen credentials required.
saas-authentication.session-management.session-fixationSee full patternAuth tokens placed in URL query parameters (CWE-598, CWE-200) are automatically recorded in browser history, server access logs, proxy logs, and the HTTP Referer header sent to any third-party resource on the next page. A token that lives in a URL has already been logged somewhere beyond your control. OWASP A02 (Cryptographic Failures) covers sensitive data exposure through insecure transport, and OWASP ASVS V7 Session Management explicitly disallows placing session identifiers in URL query strings; a token visible in a URL is effectively broadcast to every system the request passes through.
Why this severity: High because URL-embedded tokens are passively harvested from server logs and Referer headers without any active attack against the user.
saas-authentication.session-management.no-auth-tokens-in-urlSee full patternlocalStorage is synchronously readable by every JavaScript file executing on your domain — your own code, third-party analytics, CDN-hosted widgets, and any XSS payload. Auth tokens stored there are exposed to the entire JavaScript surface area of your application. CWE-922 (Insecure Storage of Sensitive Information) and CWE-312 (Cleartext Storage of Sensitive Information) both apply. OWASP A02 lists insecure credential storage as a cryptographic failure. NIST 800-63B §7.1 requires that session secrets be protected from disclosure; localStorage provides no such protection.
Why this severity: Medium because exploitation requires either a successful XSS attack or a malicious third-party script to be running on the page, but either condition is common.
saas-authentication.session-management.auth-state-not-localstorageSee full patternExtending the session lifetime to 30 days to implement 'remember me' means a stolen cookie is valid for a month with no way to revoke it on a per-device basis. CWE-613 (Insufficient Session Expiration) and CWE-287 (Improper Authentication) both cover this — the regular session has effectively lost its expiry guarantee. OWASP ASVS V3 (Session Management) treats persistent-login tokens as a separate authenticator class that must be individually revocable. A separate remember-me token stored server-side can be deleted individually, ending persistent login on one device without forcing a logout everywhere.
Why this severity: Medium because the defect requires a stolen persistent cookie to be exploited, but once stolen the session lasts weeks with no user-accessible revocation mechanism.
saas-authentication.session-management.remember-me-separate-tokenSee full patternAn unprotected login endpoint allows unlimited automated password guessing. CWE-307 (Improper Restriction of Excessive Authentication Attempts) is one of the most exploited authentication failures: a botnet can attempt millions of credential combinations against any account in minutes. NIST 800-63B §5.2.2 and PCI-DSS Req-8.3.4 both mandate throttling on authentication endpoints. OWASP A07 lists brute-force susceptibility as a named failure mode. In-memory rate limiting does not survive serverless cold starts or multi-instance deployments — Redis-backed state is required for distributed environments.
Why this severity: Critical because an unthrottled login endpoint allows automated brute-force attacks that can compromise any account given sufficient time and a common password list.
saas-authentication.auth-flow.rate-limit-loginSee full patternIP-based rate limiting alone does not stop a targeted attack on a specific account from a botnet that uses one password attempt per IP address. CWE-307 and NIST 800-63B §5.2.2 require per-account throttling in addition to per-IP limits. PCI-DSS Req-8.3.4 requires temporary lockout after no more than 10 consecutive failures. OWASP A07 lists credential stuffing and brute-force susceptibility as named failure modes. Supabase Auth provides endpoint rate limiting but does not implement configurable per-account lockout — custom lockout logic is required unless you use Clerk or Auth0 with Attack Protection enabled.
Why this severity: High because per-account lockout is the only control that stops a distributed brute-force attack targeting a single user account from many IP addresses simultaneously.
saas-authentication.auth-flow.account-lockoutSee full patternLogin CSRF (CAPEC-62) lets an attacker log a victim into an attacker-controlled account using a forged cross-site request. This enables account takeover indirectly: the victim, now logged into the attacker's account, may enter sensitive data that the attacker can later retrieve. CWE-352 (CSRF) on a login endpoint is classified under OWASP A01 (Broken Access Control); PCI-DSS v4.0 Req-6.2.4 explicitly lists cross-site request forgery among the software attacks that engineering practices must prevent. SameSite=Lax provides meaningful browser-enforced protection for most cases, but explicit CSRF token validation is required for custom endpoints that process sensitive actions on navigation.
Why this severity: Critical because login CSRF can silently associate a victim's activity with an attacker's account, enabling credential harvesting and session theft without any direct compromise of the victim's credentials.
saas-authentication.auth-flow.login-csrfSee full patternUnauthenticated access to private routes is OWASP A01 (Broken Access Control) — the top-ranked web application vulnerability. CWE-285 (Improper Authorization) and CWE-287 (Improper Authentication) both apply when any private page or API route is reachable without a valid session. In Next.js, a middleware file placed at an incorrect path is silently ignored by the framework — every route it was intended to protect is exposed, with no error and no indication anything is wrong.
Why this severity: Critical because exposed private routes allow unauthenticated access to user data, admin functions, or financial records with no credentials required.
saas-authentication.auth-flow.auth-middleware-private-routesSee full patternClearing a session cookie on the client has no effect on a session token that was already captured — by an XSS payload, a network sniff, or a shared machine where the token was read from memory. CWE-613 (Insufficient Session Expiration) applies when logout does not invalidate the server-side session record. NIST 800-63B §7.1 (Session Bindings) requires that session termination be enforced server-side, not only client-side. OWASP A07 (Identification and Authentication Failures) lists insufficient logout among its named failure modes. The server must forget the session; the cookie clear is only a UX courtesy.
Why this severity: High because client-only logout leaves a captured session token valid until its natural expiry, giving attackers continued access even after the legitimate user has explicitly logged out.
saas-authentication.auth-flow.logout-invalidates-sessionSee full patternDistinct error messages for 'email not found' versus 'wrong password' allow automated enumeration of every registered email address on your platform (CWE-204, CWE-203, CAPEC-196). The same applies to password reset endpoints that return 404 for unregistered emails. OWASP A07 covers this as an authentication information disclosure failure. Beyond security, leaking account existence violates user privacy — subscribers who registered with a personal email may not want their account existence confirmed to anyone who asks. A uniform response eliminates both the security and privacy exposure at zero cost.
Why this severity: Medium because account enumeration requires no credentials and enables targeted phishing and credential stuffing campaigns against confirmed accounts.
saas-authentication.auth-flow.auth-errors-no-email-revealSee full patternPasswords hashed with MD5, SHA-1, or unsalted SHA-256 can be brute-forced at billions of attempts per second on commodity GPU hardware. CWE-916 (Use of Password Hash With Insufficient Computational Effort) applies directly. A database breach of MD5-hashed passwords is functionally equivalent to a plaintext breach for any user with a common password. NIST SP 800-63B §5.1.1.2 (Memorized Secret Verifiers) mandates that verifiers store memorized secrets using a suitable one-way key derivation function, and OWASP A02 (Cryptographic Failures) covers the broader category. PCI-DSS v4.0 requires strong cryptography for authentication factors at rest. A cost factor below 10 for bcrypt provides insufficient slowdown on modern hardware.
Why this severity: Critical because fast-hashed or plaintext passwords are fully recoverable from a database dump, converting any breach into immediate credential exposure for all users.
saas-authentication.password-credential.password-hashing-modernSee full patternA password written to a log file does not expire, does not rotate, and does not observe the principle of least privilege — it is accessible to everyone who can read that log aggregation service. CWE-312 (Cleartext Storage of Sensitive Information) and CWE-532 (Insertion of Sensitive Information into Log File) both apply directly. PCI-DSS broadly requires protection of authentication credentials at rest and in transit, and OWASP A09 (Security Logging and Monitoring Failures) covers logging too much alongside logging too little. A single `console.log(req.body)` debug statement in the login handler can write millions of plaintext passwords to your log aggregation service before anyone notices.
Why this severity: Critical because passwords written to logs persist indefinitely, travel to third-party log services, and expose every affected user's credential regardless of whether the database is ever breached.
saas-authentication.password-credential.no-plaintext-passwords-logsSee full patternClient-side password validation is trivially bypassed by calling the API directly with curl or any HTTP client. CWE-521 (Weak Password Requirements) is only exploitable when server-side enforcement is missing. NIST 800-63B §5.1.1.2 (Memorized Secret Verifiers) sets a minimum of 8 characters and specifically warns against composition rules; PCI-DSS Req-8.3.6 requires at least 12 characters. OWASP A07 lists weak password policies as an authentication failure. A single-character password accepted by your API means every user who sets a simple password has a credential that can be brute-forced in seconds from any leaked hash.
Why this severity: Medium because weak password policy alone does not cause a breach, but it makes brute-force and credential stuffing attacks dramatically more effective when combined with any other failure.
saas-authentication.password-credential.password-strength-enforcedSee full patternA non-expiring or reusable password reset token is a persistent account takeover vector: intercept it once (from a forwarded email, a shared device, or a log entry), and you can reset the password at any time in the future. CWE-640 (Weak Password Recovery Mechanism for Forgotten Password) and CWE-262 (Not Using Password Aging) both apply. OWASP ASVS V2.5 requires that recovery tokens be short-lived, high-entropy, and single-use; OWASP A07 (Identification and Authentication Failures) lists broken account recovery as a named failure mode.
Why this severity: High because a non-expiring or reusable reset token provides account takeover capability to anyone who ever possessed the reset link, even if that access was accidental or historical.
saas-authentication.password-credential.password-reset-time-limitedSee full patternWithout email verification, any user can register with someone else's email address, potentially locking the legitimate owner out of your service, triggering unwanted emails to that person, or establishing a fraudulent account linked to a real identity. CWE-287 (Improper Authentication) applies when you grant full account access without confirming control of the supplied credential. OWASP A07 (Identification and Authentication Failures) covers unverified account creation among its failure modes, and identity-proofing frameworks in NIST SP 800-63A treat unverified claimed identifiers as a category-one enrollment weakness.
Why this severity: High because unverified accounts enable account enumeration, email harassment of third parties, and fraudulent account creation at scale with no authentication of the claimed identity.
saas-authentication.password-credential.email-verificationSee full patternPredictable recovery tokens (generated with `Math.random`, timestamps, or sequential IDs) can be brute-forced or guessed, giving attackers account recovery capability without the victim's involvement. CWE-640 (Weak Password Recovery) and CWE-338 (Use of Cryptographically Weak PRNG) both apply. Disclosing account email or username on the reset confirmation page before the token is validated reveals account existence and PII to anyone with a guess-and-click workflow. OWASP A07 covers both weak token generation and information disclosure during recovery as authentication failures.
Why this severity: Medium because successful exploitation requires either guessing a valid token or having prior access to a reset link, but weak random generation significantly reduces the guessing effort.
saas-authentication.password-credential.account-recovery-no-leakSee full patternThe OAuth state parameter is the CSRF token for the OAuth flow. Without it, an attacker can initiate an OAuth authorization on behalf of a victim and then complete the flow with the attacker's authorization code, linking the victim's account to the attacker's identity (account linking attack). CWE-352 (CSRF) and CWE-601 (Open Redirect) are both implicated in OAuth flow manipulation; CAPEC-62 documents the OAuth CSRF attack specifically. OWASP A01 (Broken Access Control) covers this when an attacker can substitute their own authorization code. State validation is a mandatory requirement of RFC 6749.
Why this severity: High because OAuth CSRF without state validation can silently link a victim's account to an attacker's social identity or trigger unauthorized account access during the callback.
saas-authentication.social-auth.oauth-state-validationSee full patternWildcard redirect URIs registered with OAuth providers allow an attacker to redirect an authorization code to any subdomain they control — including user-generated content subdomains, preview deployments, or abandoned subdomains. CWE-601 (Open Redirect) is the direct failure; CAPEC-194 documents subdomain takeover-based OAuth redirect attacks. OWASP A01 (Broken Access Control) covers the authorization code interception that results. An authorization code delivered to the wrong endpoint is equivalent to handing the attacker a short-lived session credential.
Why this severity: Info because wildcard redirect URIs require a subdomain takeover or other coincident vulnerability to exploit, but the configuration defect itself is a low-effort fix.
saas-authentication.social-auth.social-callback-whitelistSee full patternJWTs are stateless — they cannot be individually revoked before their expiry timestamp. A token with a 365-day lifetime handed to a compromised client, leaked via a log line, or obtained through an XSS payload is valid for a year with no mechanism to invalidate it. CWE-613 (Insufficient Session Expiration) and CWE-347 (Improper Verification of Cryptographic Signature) are both relevant when tokens are issued without meaningful expiry. NIST 800-63B §7.1 requires that session credentials be time-bounded. OWASP A02 covers cryptographic failure modes that include issuing tokens with no or excessive expiry.
Why this severity: High because a JWT with no expiry or a multi-year expiry cannot be invalidated after account suspension, role change, or credential compromise — the token remains valid regardless of server-side state.
saas-authentication.social-auth.jwt-reasonable-expirySee full patternPasswords are compromised constantly — through phishing, credential stuffing from other breaches, or malware. Without MFA, a leaked password is a full account takeover. CWE-308 (Use of Single-Factor Authentication) directly identifies this gap. NIST 800-63B §4.2 defines Authenticator Assurance Level 2 as requiring a second factor; PCI-DSS Req-8.4.2 mandates MFA for all access to the cardholder data environment. OWASP A07 lists missing MFA as an authentication failure. MFA is the single control with the highest documented reduction in account takeover incidents — Google reported over 99% reduction in automated attacks when TOTP was enforced.
Why this severity: Info because MFA absence does not directly enable an attack but substantially amplifies the impact of every other credential-related vulnerability in the application.
saas-authentication.social-auth.mfa-availableSee full patternAuthentication libraries receive security patches — CVEs in `next-auth`, `@supabase/supabase-js`, and similar packages have historically enabled token forgery, session bypass, and privilege escalation. CWE-1395 (Dependency on Vulnerable Third-Party Component) and OWASP A06 (Vulnerable and Outdated Components) directly cover this. SLSA L2 supply-chain provenance requires component currency verification. A library that is multiple major versions behind may lack patches for known exploitable vulnerabilities and lose access to security advisory channels entirely.
Why this severity: Info because version lag does not immediately indicate exploitation, but outdated auth libraries may contain known, publicly documented vulnerabilities with available exploits.
saas-authentication.social-auth.auth-library-versionSee full patternLogin forms without loading indicators let users click submit repeatedly while the first request is still in flight, triggering duplicate authentication attempts that can corrupt session state, burn through brute-force lockout counters, double-charge billing events on post-login redirects, and produce inconsistent MFA challenges. Missing error feedback forces users to guess why authentication failed, driving them to password managers that may paste stale credentials and accelerating account lockouts tracked under OWASP A07 (Identification & Authentication Failures). Inaccessible form labels also breach WCAG 2.2 SC 1.3.1 (Info and Relationships) and SC 4.1.2 (Name, Role, Value), excluding screen-reader users from your product.
Why this severity: Info because this is a UX polish concern, not a direct security vulnerability — authentication still functions, but duplicate submissions and silent failures degrade trust.
saas-authentication.session-management.login-ui-feedbackSee full patternHardcoded default credentials (CWE-798) in seed scripts or initialization code are one of the most targeted attack vectors — automated scanners look for accounts with passwords like 'admin123', 'password', or 'test' within minutes of a deployment. OWASP A07 includes default credentials as a named authentication failure. PCI-DSS v4.0 Req-2.2.2 requires that vendor default accounts are either removed/disabled or have their default passwords changed per Req-8.3.6. A seed script that creates an admin account without an environment guard may silently run in production during a migration or initial deploy, creating a fully privileged account with a known, public password.
Why this severity: Info because default credentials require an attacker to know or guess the account exists, but their presence in production is a high-confidence finding that warrants immediate remediation.
saas-authentication.password-credential.dev-accounts-removedSee full patternWithout auth event logging, a brute-force campaign, credential stuffing run, or account takeover leaves no trace in your infrastructure. CWE-778 (Insufficient Logging) directly applies. OWASP A09 (Security Logging and Monitoring Failures) lists insufficient logging of authentication events as a primary failure mode. PCI-DSS Req-10.2.1 mandates logging of all individual user access events. ISO 27001:2022 A.8.15 requires audit trail maintenance for all authenticated actions. When an account is compromised and you have no logs, you cannot determine scope, timeline, or affected users — incident response becomes guesswork.
Why this severity: Info because missing auth logs do not directly enable attacks, but they prevent detection, investigation, and response when attacks occur.
saas-authentication.session-management.auth-events-loggedSee full patternRun this audit in your AI coding tool (Claude Code, Cursor, Bolt, etc.) and submit results here for scoring and benchmarks.
Open Authentication Audit