
jwt-misuse-anti-pattern
Security anti-pattern for JWT misuse vulnerabilities (CWE-287). Use when generating or reviewing code that creates, validates, or uses JSON Web Tokens. Detects 'none' algorithm attacks, weak secrets, sensitive data in payloads, and missing expiration.
"Security anti-pattern for JWT misuse vulnerabilities (CWE-287). Use when generating or reviewing code that creates, validates, or uses JSON Web Tokens. Detects 'none' algorithm attacks, weak secrets, sensitive data in payloads, and missing expiration."
JWT Misuse Anti-Pattern
Severity: High
Summary
JSON Web Tokens (JWTs) are a common standard for creating access tokens, but they are frequently misused, leading to significant security vulnerabilities. This anti-pattern covers several common JWT implementation flaws often seen in AI-generated code, including accepting the "none" algorithm, using weak secrets, storing sensitive data in the payload, and failing to set an expiration time. These mistakes can lead to authentication bypass, token forgery, and sensitive data exposure.
The Anti-Patterns and Solutions
1. Algorithm Confusion ("none" Algorithm Attack)
A critical vulnerability where a library accepts any algorithm specified in the token's header. An attacker can change the algorithm to "none" and remove the signature, causing the library to validate the token without any cryptographic checks.
BAD Code Example
# VULNERABLE: Accepts whatever algorithm is in the header
import jwt
def verify_jwt_vulnerable(token, secret_key):
# If the token's header is {"alg": "none"}, the library may bypass signature verification entirely.
try:
decoded = jwt.decode(token, secret_key, algorithms=None) # algorithms=None or not specified
return decoded
except jwt.PyJWTError as e:
print(f"JWT verification failed: {e}")
return None
GOOD Code Example
# SECURE: Explicitly specify allowed algorithms
import jwt
def verify_jwt_secure(token, secret_key):
# CRITICAL: Always specify the exact algorithm(s) you expect.
# The library will now reject any token that does not use one of the specified algorithms.
try:
decoded = jwt.decode(token, secret_key, algorithms=["HS256", "RS256"])
return decoded
except jwt.PyJWTError as e:
print(f"JWT verification failed: {e}")
return None
2. Weak Secret
Using a weak, predictable, or hardcoded secret for symmetric signing algorithms (like HS256) makes it possible for an attacker to brute-force the secret and forge valid tokens.
BAD Code Example
# VULNERABLE: Weak or short secret key
import jwt
JWT_SECRET = "secret123" # Easily brute-forced!
def create_jwt(user_id):
payload = {"user_id": user_id}
return jwt.encode(payload, JWT_SECRET, algorithm="HS256")
GOOD Code Example
# SECURE: Strong, centrally managed secret
import jwt
import os
# Load a strong, randomly generated secret from environment variables or a secret manager.
JWT_SECRET = os.environ.get("JWT_SECRET")
def initialize():
if not JWT_SECRET or len(JWT_SECRET) < 32:
raise ValueError("JWT_SECRET must be at least 256 bits (32 chars) for HS256")
# For production, consider asymmetric keys (e.g., RS256) where the private key is kept secret
# and the public key can be safely distributed for verification.
def create_jwt_asymmetric(user_id, private_key):
payload = {"sub": user_id}
return jwt.encode(payload, private_key, algorithm="RS256")
3. Sensitive Data in Payload
The JWT payload is Base64Url-encoded, not encrypted. Anyone who intercepts the token can easily decode and read the data it contains. Storing sensitive information like PII, passwords, or internal data in the payload is a major security risk.
BAD Code Example
# VULNERABLE: Sensitive data in JWT payload
import jwt
def create_jwt_with_pii(user, secret_key):
payload = {
"user_id": user.id,
"email": user.email,
"ssn": user.social_security_number, # PII EXPOSED!
"password_hash": user.password_hash # CRITICAL RISK!
}
return jwt.encode(payload, secret_key, algorithm="HS256")
GOOD Code Example
# SECURE: Minimal, non-sensitive claims
import jwt
import time
def create_jwt_secure(user, secret_key):
payload = {
"sub": user.id, # Subject (user ID) - standard and non-sensitive
"iat": int(time.time()), # Issued at - standard
"exp": int(time.time()) + 3600, # Expiration (1 hour) - standard
"role": user.role # Non-sensitive custom claim
}
# Never include passwords, PII, payment info, or internal data.
# The server should fetch this data from a secure database using the user ID from the token.
return jwt.encode(payload, secret_key, algorithm="HS256")
Detection
- Review calls to
jwt.decode()and ensure thealgorithmsparameter is explicitly set to a list of expected algorithms. - Search for hardcoded or weak JWT secrets (e.g.,
"secret","password", short keys). - Inspect the data being added to the JWT payload for any sensitive information (PII, credentials, etc.).
- Check for the absence of the
exp(expiration) claim when creating tokens.
Prevention
- [ ] Always specify allowed algorithms explicitly during token verification.
- [ ] Use strong, centrally managed secrets (at least 256 bits for HS256) or prefer asymmetric algorithms (RS256/ES256) for production systems.
- [ ] Never store sensitive data in JWT payloads. The payload is readable by anyone.
- [ ] Always include an
expclaim with a reasonably short lifetime for access tokens. - [ ] Implement a token refresh mechanism for sessions that need to last longer than the access token's lifetime.
- [ ] Consider implementing a token revocation list to invalidate tokens for compromised accounts.
Related Security Patterns & Anti-Patterns
- Hardcoded Secrets Anti-Pattern: JWT secrets are a common type of hardcoded secret.
- Session Fixation Anti-Pattern: Provides context on alternative session management strategies.
- Insufficient Randomness Anti-Pattern: Relevant if generating unique token identifiers (
jti).
References
You Might Also Like
Related Skills

create-pr
Creates GitHub pull requests with properly formatted titles that pass the check-pr-title CI validation. Use when creating PRs, submitting changes for review, or when the user says /pr or asks to create a pull request.
n8n-io
electron-chromium-upgrade
Guide for performing Chromium version upgrades in the Electron project. Use when working on the roller/chromium/main branch to fix patch conflicts during `e sync --3`. Covers the patch application workflow, conflict resolution, analyzing upstream Chromium changes, and proper commit formatting for patch fixes.
electron
pr-creator
Use this skill when asked to create a pull request (PR). It ensures all PRs follow the repository's established templates and standards.
google-gemini
clawdhub
Use the ClawdHub CLI to search, install, update, and publish agent skills from clawdhub.com. Use when you need to fetch new skills on the fly, sync installed skills to latest or a specific version, or publish new/updated skill folders with the npm-installed clawdhub CLI.
moltbot
tmux
Remote-control tmux sessions for interactive CLIs by sending keystrokes and scraping pane output.
moltbot
create-pull-request
Create a GitHub pull request following project conventions. Use when the user asks to create a PR, submit changes for review, or open a pull request. Handles commit analysis, branch management, and PR creation using the gh CLI tool.
cline