Broken User Authentication ranks as the second most critical vulnerability in the OWASP API Security Top 10 for 2023. In bug bounty programs, authentication flaws often lead to account takeover, data breaches, and high-severity payouts.
Unlike traditional web applications, APIs use stateless tokens, OAuth flows, and machine-to-machine communication patterns. This creates unique attack surfaces that many testers overlook. This guide covers the ten most critical API authentication vulnerabilities with practical testing techniques.
What Makes API Authentication Different
Standard web apps rely on session cookies and server-side state. APIs use tokens that carry all authentication information within the request itself. Every request must prove its identity independently.
This stateless design introduces specific vulnerabilities. JWT tokens can be manipulated. Refresh tokens can be replayed. OAuth flows have multiple redirects where things go wrong. Understanding these differences is the first step to finding bugs.
The Ten Critical Vulnerabilities
1. JWT Algorithm Confusion
JSON Web Tokens include an alg header that tells the server which signing algorithm was used. When servers trust this header without strict validation, attackers can bypass signature verification.
The none algorithm attack works because some libraries accept unsigned tokens. Setting alg: "none" removes the signature requirement entirely. The server processes the token as valid.
The RS256 to HS256 confusion attack is more subtle. RS256 uses RSA private keys for signing and public keys for verification. HS256 uses a shared secret. If a server expects RS256 but receives HS256, it may verify the signature using the public key as an HMAC secret. Attackers who know the public key can forge valid tokens.
Testing requires intercepting a valid JWT, modifying the alg header, and sending the modified token to protected endpoints.
2. JWT Key ID Injection
The kid header specifies which key should verify the token. Servers often fetch this key from files, databases, or external URLs. When kid is not sanitized, injection attacks become possible.
Path traversal via kid: "../../../dev/null" can read local files. If the server uses file contents as verification keys, attackers control the key.
SQL injection in kid works when servers query a database for the key. A payload like ' UNION SELECT 'public_key can return attacker-controlled values.
SSRF attacks use kid: "http://internal-service/secret" to force the server into fetching from attacker-specified locations.
Testing requires modifying the kid value to various injection payloads and observing server behavior.
3. Weak JWT Secrets
Many developers generate JWT secrets manually. Common choices include "secret", "changeme", "password", or simple strings. These are vulnerable to brute-force attacks.
Hashcat with mode 16500 cracks JWT secrets. RockYou wordlist contains thousands of common secrets. Tools like jwt_tool and crackjwt automate this process.
A secret with low entropy can be cracked in minutes on modern hardware. Even longer secrets that follow dictionary patterns are vulnerable.
Testing involves capturing a valid JWT and attempting to crack its secret offline. No rate limits apply because the attack happens on your own machine.
4. Missing Token Expiration
JWTs can include an exp claim that defines expiration time. Without this claim, tokens remain valid forever. Some implementations set expiration to years in the future or never check it at all.
An attacker who captures a token once can reuse it indefinitely. This is especially dangerous for tokens leaked in logs, browser history, or network traffic.
Testing requires capturing a token, waiting for its supposed expiration, and attempting to reuse it. Also check if the exp claim exists and whether the server rejects expired tokens.
5. Refresh Token Reuse Without Rotation
Refresh tokens allow clients to obtain new access tokens without re-authenticating. The secure pattern is one-time use with rotation. Each refresh request returns a new refresh token and invalidates the old one.
Without rotation, stolen refresh tokens remain valid forever. An attacker can generate unlimited access tokens from a single stolen refresh token.
Testing involves using a refresh token to obtain new tokens, then using the same refresh token again. If the second request succeeds, rotation is missing.
6. Predictable Password Reset Tokens
Password reset flows generate tokens sent via email or SMS. When these tokens follow predictable patterns, attackers can brute-force them.
Common flaws include 4-digit or 6-digit numeric codes with no rate limiting. An attacker can try all 10,000 combinations in minutes.
Time-based tokens using milliseconds or seconds since epoch are also predictable. If an attacker can guess the approximate reset request time, they can narrow the search space.
Tokens returned in API responses during the reset request represent the most critical flaw. The attacker can simply read the token from the response body.
Testing requires requesting multiple resets and analyzing token patterns. Check for sequential increases, timestamp encoding, or short numeric values.
7. No Rate Limiting on Authentication Endpoints
Login, OTP verification, password reset, and token issuance endpoints require rate limiting. Without it, brute-force attacks become feasible.
Four-digit OTP codes need only 10,000 attempts. With no rate limits, this takes minutes. Credential stuffing using breached password lists becomes trivial.
Rate limiting should apply per user, per IP address, and globally. It should also increase delays after repeated failures.
Testing involves sending 100 or more rapid requests to authentication endpoints. Use Burp Intruder or a simple Python script. If all requests succeed, rate limiting is missing.
8. Verbose Error Messages Enabling Account Enumeration
Authentication endpoints should return identical responses for all failure cases. When they differentiate, attackers can enumerate valid users.
Different messages like "Password incorrect" versus "User not found" reveal whether an account exists. Registration endpoints that say "Email already registered" provide the same information.
Response timing differences can also leak information. Checking an existing user might take longer because the server fetches the user record first.
Testing requires comparing responses for known valid and known invalid inputs. Look for differences in status codes, response bodies, or response times.
9. OAuth 2.0 Misconfiguration
OAuth flows involve multiple redirects where tokens pass through the browser. Each redirect is an attack opportunity.
The redirect_uri parameter tells the OAuth provider where to send the authorization code. When validation is missing, attackers can set their own domain and steal codes.
Open redirects in redirect_uri allow attackers to leak codes via the Referer header. The code travels from the legitimate site to the attacker's site automatically.
Missing CSRF protection on the state parameter enables attackers to initiate flows and intercept responses. The state parameter should be unpredictable and tied to the user session.
Testing requires attempting to change redirect_uri to external domains, open redirect endpoints, or localhost addresses.
10. Exposed API Keys in URLs and Client Code
API keys in URLs appear in browser history, server logs, and Referer headers. Anyone with access to these logs can steal the key.
Mobile applications and single-page apps often hardcode API keys in JavaScript or configuration files. These are trivially extractable.
Debug endpoints, source maps, and public repositories are common leakage sources. Developers sometimes commit keys to GitHub despite best efforts.
Testing involves checking network traffic, browser developer tools, JavaScript files, and public code repositories for exposed keys.

Top comments (0)