Choose your stack

Node.js · Express

Fix missing authentication for a critical function in Node.js and Express

Verify a credential on the server before any critical route runs.

Open the fix card
Python · Flask

Fix missing authentication in Python and Flask

Authenticate the operator, do not trust the network or a client-supplied header.

Open the fix card
Java · Spring Boot

Fix missing authentication for a critical function in Java and Spring Boot

Verify a credential on the server before any critical route runs.

Open the fix card
C# · ASP.NET Core

Fix missing authentication for a critical function in C# and ASP.NET Core

Verify a credential on the server in your authentication handler, then require it on every protected endpoint.

Open the fix card
TypeScript · Next.js

Fix missing authentication for a critical function in Next.js

Verify a credential on the server in every protected route handler.

Open the fix card
Python · FastAPI

Fix missing authentication in Python and FastAPI

Put an authentication dependency on every protected path operation.

Open the fix card
Python · Django

Fix missing authentication in Python and Django

Authenticate the operator, do not trust the network or a client header.

Open the fix card
Go · net/http

Fix missing authentication in Go and net/http

Make every critical route go through one authentication step that verifies a credential the server issued: here a Bearer token whose HMAC-SHA256 is checked with hmac.Equal.

Open the fix card
Ruby · Rails

Fix missing authentication in Ruby on Rails

Keep the before_action :authenticate in ApplicationController so every action needs it, and skip_before_action only on the public health route.

Open the fix card
PHP · Laravel

Fix missing authentication in PHP and Laravel

Put every critical route behind one middleware that verifies a server-issued credential: here a Bearer token whose HMAC-SHA256 is checked with hash_equals.

Open the fix card

How it happens

  • The route has no authentication at all. A dashboard, metrics, export or internal admin endpoint is shipped reachable by anyone who knows the path (CWE-306). "It's not linked anywhere" is not authentication.
  • Identity is read from the request. The handler trusts a userId in the query string or body, so the caller answers the authentication question themselves and reads any account by changing the value.
  • A client-settable header is trusted. The app believes an upstream proxy sets and strips X-Authenticated-User (or X-Forwarded-User), but the service is reachable without the proxy, so a client sends the header and becomes anyone. The check exists but verifies nothing (CWE-287).
  • The guard protects one route and misses a sibling. A detail endpoint is fixed after a review while a new /export or /me.json ships without the check, or a middleware matcher skips a route group.
  • A present-but-unverified token is treated as proof. The code checks that a token exists rather than validating it against a session store or a signature, so any non-empty value is accepted.

Fix principles

  • Treat every route as protected unless you decided it is public. Decide which one or two endpoints are genuinely public (a liveness check) and guard the rest.
  • Write one authentication guard: read the credential, verify it against server-side state (a session store, or a signed token you validate), set the user from the result, and answer 401 on anything absent, unknown or malformed.
  • Apply the guard on every protected route, by mounting it on the router or area rather than repeating per-handler decisions; a new route is then covered by default. Where a framework uses edge middleware, keep a check in the handler too, because matchers miss routes.
  • Take the user, tenant and role only from the verified credential. Never read identity from the query string, the body, or a header the client can set.
  • Keep internal-only endpoints (metrics, health detail, configuration) behind the guard, or strip them to data that is safe to expose.
  • Remember authentication is not authorization: once the caller is known, still check that they may perform the specific action or read the specific object.

The scenario

An account service exposes GET /health (public), GET /me (the caller's own profile) and GET /admin/metrics (an internal figure). /me and /admin/metrics are critical functions that must not run without a caller. The credential is an opaque bearer token looked up in a server-side sessions table; the fixtures seed a few users and sessions, and the fixed guard returns the stored user or 401. The vulnerable build takes identity from the request; the wrong build trusts a client-set header.

How the cards prove it

  • Run each card's tests in three modes: the fixed implementation must pass, and the vulnerable and the plausible-but-wrong implementations must fail. run-all.mjs does this for every card.
  • The exploit tests call each protected route with no credential, with a forged identity header, and with a made-up token, and assert 401 with no user data. The functional tests keep a valid session and a public health route working.
  • On a running system, enumerate every route that returns user or internal data and call each with no Authorization header, a forged proxy header, and a random token; each must get 401. Confirm a route added since the last review is covered by the guard.
  • Do not count on static analysis: no Semgrep registry rule or CodeQL query for these stacks knows which routes must be authenticated, and the OWASP Top 10 pack reported nothing on the vulnerable code. Each card's scannerRules records what was checked.

Identifiers

CWE-306 (Missing Authentication for Critical Function) is the weakness the cards are named after: a route that returns user or internal data runs with no verified caller. CWE-287 (Improper Authentication), its parent, covers the wrong implementation, whose check exists but verifies nothing, trusting a header the client sets. Both map to OWASP Top 10:2025 A07 Authentication Failures (A07's official CWE list includes CWE-306 and CWE-287) and to API2:2023 Broken Authentication. CAPEC-12 (Choosing Message Identifier) and CAPEC-36 (Using Unpublished Interfaces or Functionality) are two of the attack patterns MITRE links to CWE-306. The 2025 CWE Top 25 does not rank CWE-306.

Attack patterns:

References

  1. OWASP Top 10:2025 A07 Authentication Failures
  2. OWASP API Security Top 10 2023: API2 Broken Authentication
  3. CWE-306: Missing Authentication for Critical Function
  4. CWE-287: Improper Authentication
  5. OWASP Authentication Cheat Sheet
  6. OWASP Session Management Cheat Sheet

Practice in the browser

Guides on this weakness

Guide

Verify webhook deliveries before acting

Verify the provider’s signature over the correct bytes, then apply replay, authorization, and idempotency controls before a business action.

Guide

Maintain an API inventory and prevent gateway bypass

Connect documented routes, deployed listeners and backend trust so retired or direct paths do not bypass the intended controls.

Guide

Defend JWTs against forgery, confusion and replay

Verify a JWT as an issuer-, type- and audience-bound assertion with an algorithm allowlist and trusted keys, closing the alg "none", key-confusion, header-injection, weak-secret and replay attacks.

Guide

Defend OAuth and OIDC against redirect and token attacks

Apply RFC 9700 and RFC 10017: exact redirect matching, PKCE with downgrade protection, state and iss binding, refresh-token rotation, sender-constrained tokens, and a backend-for-frontend so browser tokens cannot be stolen.

Guide

Publish security advisories with CSAF, VEX, CVE records and OSV

What a useful security advisory contains and how to publish it in the formats tools read: a validated CSAF 2.0 VEX document, the CSAF provider files, CVE records through a CNA (CVE Record Format 5.2), and OSV records for open-source packages. Covers the status of CSAF 2.1 as of October 2026.

Case study

Case study: ingress-nginx CVE-2025-1974 and the exposed admission webhook (2025)

How an admission webhook open to the whole Pod network made ingress-nginx's configuration-injection bugs a 9.8 cluster-takeover risk in 2025, and what its 2026 retirement means.

Case study

Case study: First American's EaglePro document exposure (2019)

How sequential IDs in unauthenticated links exposed First American's title documents in 2019, after its own penetration test found the flaw and a clerical error let it go unfixed.