Skip to main content

Common Misconfiguration

Weak or exposed JWT secrets allow attackers to forge tokens, bypass authentication, and gain unauthorized access to systems.

Vulnerable Example

Secure Example

Detection Patterns

  • JWT Token Format: `eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+`
  • Algorithm “none” Vulnerability: `("alg"|"algorithm")\s*:\s*("none"|"None")`
  • Common Weak Secret: `(secret|password)['"]?\s*[:=]\s*['"](secret|12345|admin|jwt|super-secret)['"]`
  • Hardcoded Secret Variable: `(JWT_SECRET|SECRET_KEY)\s*[:=]\s*['"][^'"]{1,20}['"]` (Finds short, likely weak secrets)

Prevention Best Practices

  1. Use Strong, Random Secrets: A weak, guessable secret (like ‘secret123’) makes your token forgeable. Use a cryptographically secure random string (at least 256 bits / 32 characters) and load it from a secrets manager or environment variable.
  2. Prefer Asymmetric Algorithms (RS256): HS256 (symmetric) uses one secret to sign and verify. RS256 (asymmetric) uses a private key to sign and a public key to verify. This is safer because you can share the public key with other services for verification without exposing the private signing key.
  3. Short Access Token Expiration: Access tokens (which grant access) should be very short-lived (e.g., 5-15 minutes). This dramatically limits the window of opportunity if a token is stolen.
  4. Implement Token Refresh: Use a separate, long-lived “refresh token” (e.g., 7 days) to get a new access token. This refresh token should be stored securely (as an httpOnly cookie) and ideally implement rotation (where using a refresh token invalidates it and issues a new one).
  5. Minimal, Non-Sensitive Payload: A JWT is signed (tamper-proof) but not encrypted (it’s Base64 encoded, which is reversible). Anyone can read its contents. Never put sensitive data like passwords, permissions, or PII in the payload. Use the sub (subject) claim to store the user ID and nothing more.
  6. Validate All Claims: On the server, always verify the signature. Also, verify the exp (expiration), iss (issuer), and aud (audience) claims to ensure the token is not expired and was intended for your specific service.
  7. Implement Token Revocation: JWTs are stateless, which means they are valid until they expire. For critical events (like a user logging out or changing their password), you need a way to “revoke” their token. This usually involves maintaining a “denylist” (e.g., in Redis) of token IDs that are no longer valid.
  8. Secure Client-Side Storage: Do not store JWTs in localStorage on the client, as it’s vulnerable to XSS attacks. Store them in secure, httpOnly cookies, which cannot be accessed by JavaScript.
  9. Monitor for Token Anomalies: Log and alert on token verification failures, attempts to use expired tokens, or impossible-to-achieve token refreshes. This can indicate an attacker is trying to forge or replay tokens.
  10. Rotate Your Keys: The secrets and private keys used to sign tokens should be rotated regularly (e.g., every 90 days). This limits the lifespan of any key that might have been leaked.