๐ What Is It?
Authentication Failures covers every way an application fails to reliably confirm who is making a request and to keep that confirmation trustworthy for the life of a session. It is the 2025 evolution of A07:2021 Identification and Authentication Failures (itself the 2017 "Broken Authentication"), broadened to today's reality: passkeys, federated sign-in, and short-lived tokens. At its core, a failure occurs whenever an attacker can obtain, guess, forge, or reuse proof of identity that belongs to someone else โ leading directly to account takeover.
A07OWASP 2025 Rank
CWE-287Core: Improper Authentication
Since '17In Top 10 every edition
โ ๏ธ Top Attack Vectors
- Credential stuffing / spraying: replay breached password pairs, or one common password against many accounts (CWE-307).
- Account enumeration: different message, status, or timing reveals which accounts exist.
- Session fixation / weak IDs: ID not rotated on login, or low-entropy / predictable (CWE-384).
- MFA fatigue & AitM relay: push-bombing, or a reverse-proxy phishing kit relaying OTPs to steal the session cookie.
- Weak reset flows: guessable / non-expiring tokens, or host-header link poisoning (CWE-640).
- JWT / OAuth flaws:
alg:none, algorithm confusion, missingexp/iss/aud, looseredirect_uri, missingstate/PKCE.
๐ด Attack Flow
1. Enumerate valid usernames/emails
โ
2. Acquire creds (stuff, spray, or AitM phish)
โ
3. Bypass second factor (fatigue, SIM-swap, OTP relay)
โ
4. Take over the session (fixation, stolen cookie, forged JWT)
โ
5. PERSIST: long-lived token + attacker MFA device
โ
2. Acquire creds (stuff, spray, or AitM phish)
โ
3. Bypass second factor (fatigue, SIM-swap, OTP relay)
โ
4. Take over the session (fixation, stolen cookie, forged JWT)
โ
5. PERSIST: long-lived token + attacker MFA device
โ Vulnerable Code
// Node/Express โ enumerable, no rotation, no throttle, no MFA
app.post('/login', async (req, res) => {
const user = await db.user.findByEmail(req.body.email);
if (!user)
return res.status(404).json({ error: 'No account with that email' }); // leaks existence
const ok = await bcrypt.compare(req.body.password, user.hash);
if (!ok)
return res.status(401).json({ error: 'Incorrect password' }); // leaks existence
req.session.userId = user.id; // no session rotation -> fixation
res.json({ token: user.id }); // predictable "token"
});
โ Secure Code
// Uniform response + constant work, rotate the session, gate on MFA
const DUMMY_HASH = '$2b$12$....placeholder....'; // so unknown users cost the same
app.post('/login', loginLimiter, accountThrottle, async (req, res) => {
const user = await db.user.findByEmail(String(req.body.email).toLowerCase());
const ok = await bcrypt.compare(req.body.password, user ? user.hash : DUMMY_HASH);
if (!user || !ok)
return res.status(401).json({ error: 'Invalid email or password' }); // uniform
if (user.mfaEnabled) { req.session.pendingUserId = user.id;
return res.json({ mfaRequired: true }); }
req.session.regenerate(() => { // NEW id kills fixation
req.session.userId = user.id; req.session.save(() => res.json({ ok: true }));
});
});
โ Prevention Checklist
- Favor length over composition; screen against breach corpora (HIBP k-anonymity)
- Hash with Argon2id / scrypt / bcrypt โ never fast/unsalted
- Throttle per-account and per-source; step-up CAPTCHA over naive lockout
- Enforce MFA on sensitive actions; prefer phishing-resistant passkeys/WebAuthn
- CSPRNG session IDs; rotate on login/privilege change; invalidate server-side on logout
- Cookies:
HttpOnly,Secure,SameSite, idle + absolute timeout - Reset tokens: hashed, single-use, short expiry; build links from a trusted origin
- Pin the JWT algorithm; validate
exp/iss/aud; exactredirect_uri+state+ PKCE
๐ Detection & Tools
Burp Suite
Hydra
OWASP ZAP
jwt_tool
HaveIBeenPwned API
WebAuthn / passkeys
Quick Tips:
- DO NOT return distinct messages/timing for unknown vs. wrong-password
- DO NOT accept
alg:noneor let the token pick its algorithm - DO rotate the session ID at every privilege boundary
- DO move privileged users to phishing-resistant MFA
Key Takeaway: The attack vectors chain (enumerate โ spray โ stuff โ bypass MFA โ hijack session โ persist), so defenses must be layered. Closing enumeration alone, or adding phishable MFA alone, still leaves a viable path to account takeover.
Myth to drop: "We have MFA, so we're safe." SMS and TOTP are phishable โ an adversary-in-the-middle page relays the code in real time. Only origin-bound WebAuthn/passkeys defeat it.