v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
HIGH AI PREVALENCE: HIGH auth.py.jwt.no-verify

A JWT is decoded with signature verification disabled.

Why AI tools produce this: AI coding tools generate this anti-pattern by default, it appears in a large share of AI-written auth code.

Why this matters

PyJWT's jwt.decode(token, verify=False) (legacy) or options={"verify_signature": False} parses the token WITHOUT checking the signature, so any attacker-forged token is accepted, a complete authentication bypass.

Always verify: jwt.decode(token, key, algorithms=["RS256"]). If you only need to read an unverified header (e.g. the kid before fetching the key), use jwt.get_unverified_header(token) and treat the claims as untrusted.

VULNERABLE
vulnerable.py
import jwt


def read_legacy(token: str):
    # ruleid: auth.py.jwt.no-verify
    return jwt.decode(token, verify=False)


def read_legacy_with_key(token: str, key: str):
    # ruleid: auth.py.jwt.no-verify
    return jwt.decode(token, key, algorithms=["HS256"], verify=False)


def read_options(token: str):
    # ruleid: auth.py.jwt.no-verify
    return jwt.decode(token, options={"verify_signature": False})


def read_options_mixed(token: str, key: str):
    # ruleid: auth.py.jwt.no-verify
    return jwt.decode(token, key, options={"verify_aud": False, "verify_signature": False})
SAFE
safe.py
import jwt


# ok: auth.py.jwt.no-verify -- signature verified with an explicit algorithm
def read_verified(token: str, key: str):
    return jwt.decode(token, key, algorithms=["RS256"])


# ok: auth.py.jwt.no-verify -- verification on, only audience check disabled
def read_partial(token: str, key: str):
    return jwt.decode(token, key, algorithms=["HS256"], options={"verify_aud": False})


# ok: auth.py.jwt.no-verify -- reading the unverified header is the supported safe API
def read_header(token: str):
    return jwt.get_unverified_header(token)

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

# oauthlint-disable-next-line auth.py.jwt.no-verify -- <reason>

References

https://pyjwt.readthedocs.io/en/stable/api.html#jwt.decode ↗https://cwe.mitre.org/data/definitions/347.html ↗