| name | authentication-failures |
| description | Use this skill whenever you need to audit, test, or fix Authentication Failures (OWASP A07:2025) in Python web applications — especially FastAPI and Flask. Triggers include: any mention of JWT security, session management, brute force protection, credential stuffing, password policy, MFA enforcement, login rate limiting, session fixation, token validation, or auth-related error messages. Also trigger for requests to "check authentication", "audit login flows", "test auth security", "find auth bugs", or any task involving CWEs: CWE-287, CWE-307, CWE-384, CWE-521, CWE-798, CWE-613. Use proactively whenever the user shares auth-related code (routes, middleware, decorators, token handlers) even if they haven't explicitly mentioned security testing.
|
Authentication Failures — OWASP A07:2025
Rank: #7 (stable) | CWEs covered: 36 | Occurrences: 1.1 million+
New 2025 threat: Hybrid password attacks / password spray — attackers increment
leaked credentials (e.g., Password1! → Password2!).
What This Skill Covers
Authentication Failures occur when an application's identity verification mechanisms
are absent, weak, or bypassable. Key attack patterns:
- Credential stuffing / brute force — automated login attempts using leaked creds
- Weak/default passwords — accounts created with guessable or known-breached passwords
- Insecure credential recovery — password reset flows that leak information or are bypassable
- Missing or bypassed MFA — no second factor, or MFA that can be skipped
- Exposed session identifiers — tokens in URLs, logs, or referrer headers
- Session fixation — attacker sets a known session ID before authentication
- Improper session invalidation — sessions that survive logout or token revocation
Testing Checklist for FastAPI & Flask
Work through each section systematically. Mark ✓ pass, ✗ fail, N/A where not applicable.
1. JWT Implementation
token = jwt.encode(
{"sub": user_id, "exp": datetime.utcnow() + timedelta(minutes=15),
"iss": "myapp", "aud": "myapp-client"},
settings.SECRET_KEY, algorithm="HS256"
)
jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"],
audience="myapp-client", issuer="myapp")
jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256", "RS256", "none"])
Checks:
2. Rate Limiting on Auth Endpoints
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
@app.post("/login")
@limiter.limit("5/minute")
async def login(request: Request, credentials: LoginSchema):
...
from flask_limiter import Limiter
limiter = Limiter(app, key_func=get_remote_address, default_limits=["200/day"])
@app.route("/login", methods=["POST"])
@limiter.limit("5 per minute")
def login():
...
Checks:
3. Password Policy & Breached-Password Checking
import hashlib, httpx
def is_pwned(password: str) -> bool:
sha1 = hashlib.sha1(password.encode()).hexdigest().upper()
prefix, suffix = sha1[:5], sha1[5:]
resp = httpx.get(f"https://api.pwnedpasswords.com/range/{prefix}")
return suffix in resp.text
def validate_password(password: str):
if len(password) < 12:
raise ValueError("Password must be at least 12 characters")
if is_pwned(password):
raise ValueError("Password found in known data breach")
Checks:
4. Session Management (Flask)
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
PERMANENT_SESSION_LIFETIME=timedelta(hours=1),
)
@app.route("/logout")
@login_required
def logout():
logout_user()
session.clear()
return redirect("/login")
Checks:
5. Error Message Enumeration
if not user:
return {"error": "Username not found"}
if not verify_password(password, user.hashed_password):
return {"error": "Incorrect password"}
if not user or not verify_password(password, user.hashed_password):
return JSONResponse({"error": "Invalid credentials"}, status_code=401)
Checks:
6. Default Credentials & Hard-coded Secrets
ADMIN_PASSWORD = "admin"
TEST_USER = {"username": "test", "password": "test123"}
JWT_SECRET = "supersecretkey"
JWT_SECRET = os.environ["JWT_SECRET"]
Checks:
7. MFA Enforcement
Checks:
Key CWEs Reference
| CWE | Name | Typical Finding |
|---|
| CWE-287 | Improper Authentication | Missing auth check, bypassable auth |
| CWE-307 | Unrestricted Auth Attempts | No rate limit on login endpoint |
| CWE-384 | Session Fixation | Session ID not regenerated post-login |
| CWE-521 | Weak Password Requirements | No minimum length/complexity enforced |
| CWE-798 | Hard-coded Credentials | Secrets in source code |
| CWE-613 | Insufficient Session Expiration | Sessions survive logout; no timeout |
Automated Scanning Commands
bandit -r . -ll -ii
bandit -r . -t B105,B106,B107,B108
pip-audit
safety check
pip show python-jose PyJWT authlib
Remediation Priority Order
- Critical: JWT algorithm confusion /
"none" accepted → immediate fix
- Critical: No rate limiting on login → add
slowapi/Flask-Limiter immediately
- High: Hard-coded secrets in source → move to environment variables
- High: Sessions not invalidated on logout → fix session management
- Medium: Username enumeration via error messages → unify error responses
- Medium: No breached-password check → integrate HaveIBeenPwned API
- Low: Missing MFA option → plan rollout for privileged accounts first
References