Interactive Playground
Experiment with the vulnerable code and security rule below. Edit the code to see how the rule detects different vulnerability patterns.
pathfinder scan --ruleset python/PYTHON-JWT-SEC-003 --project .About This Rule
Understanding the vulnerability and how it is detected
This rule detects jwt.decode() calls where signature verification might be disabled. The dangerous pattern is passing options={"verify_signature": False} to jwt.decode(), which tells PyJWT to skip signature checking entirely. The result is the same as using algorithm="none" -- any token, forged or modified, will be accepted.
This pattern appears more often than you'd expect. Developers disable verification during debugging ("I just want to read the claims"), forget to re-enable it, and ship it to production. Or they disable it because they're "verifying the token elsewhere" -- but that elsewhere doesn't exist or has its own bugs.
The rule currently operates at audit level, flagging all jwt.decode() calls for review. This is because the insecure configuration is a nested dict value (options={"verify_signature": False}) that the engine can't precisely match yet. Future engine updates will add nested keyword matching to flag only the unsafe configuration.
Security Implications
Potential attack scenarios if this vulnerability is exploited
Token Tampering
Without signature verification, an attacker can modify any field in the JWT payload -- user ID, role, permissions, expiration -- and the application will accept the modified token as valid. The signature exists specifically to prevent this.
Identity Spoofing
An attacker can decode their own low-privilege token, change the subject claim to another user's ID, and submit it. Without signature verification, the application can't tell the difference between a legitimate token and a forged one.
Session Hijacking
If tokens aren't verified, an attacker doesn't even need to steal a valid token. They can create one from scratch with any claims they want. This bypasses all session management controls.
Expiration Bypass
Disabling verify_signature often disables expiration checking too, depending on the options dict. An attacker with an expired token can keep using it indefinitely.
How to Fix
Recommended remediation steps
- 1Never set verify_signature to False in production -- if you need to read claims without verification, use jwt.decode(token, options={"verify_signature": False}) only in debug/test code and gate it behind an environment check
- 2Always pass an explicit algorithms list to jwt.decode() to prevent algorithm confusion attacks
- 3Use options={"require": ["exp", "iat"]} to ensure tokens have required claims
- 4Consider wrapping jwt.decode() in a helper function that enforces verification, so individual call sites can't accidentally disable it
- 5In PyJWT 1.x, the parameter was verify=False -- if you're migrating from 1.x to 2.x, search for both patterns
Detection Scope
How Code Pathfinder analyzes your code for this vulnerability
This rule matches all jwt.decode() calls resolved through the PyJWT library using QueryType-based type inference. It currently operates as an audit rule that flags all jwt.decode() calls for review. The rule cannot yet distinguish between safe decodes (with verification) and unsafe decodes (with verify_signature=False) because this requires nested keyword argument matching into the options dict.
Compliance & Standards
Industry frameworks and regulations that require detection of this vulnerability
References
External resources and documentation
Similar Rules
Explore related security rules for Python
JWT None Algorithm
Detects jwt.encode() calls using algorithm='none', which creates unsigned tokens that anyone can forge.
JWT Hardcoded Secret
Finds jwt.encode() calls where the signing secret is a hardcoded string instead of a runtime configuration value.
Flask SQL Injection via Tainted String
Finds user input reaching raw SQL queries in Flask apps where parameterized queries should be used instead.
Frequently Asked Questions
Common questions about Unverified JWT Decode
New feature
Get these findings posted directly on your GitHub pull requests
The Unverified JWT Decode rule runs in CI and posts inline review comments on the exact lines — no dashboard, no SARIF viewer.