Skip to content

[Security] HIGH: RSA JWK parameter validation missing; MEDIUM: SHA-1 in RSA_OAEP; algorithms=None bypass #417

Description

@Nothern131

python-jose Security Vulnerability Report

Target: https://github.com/mpdavis/python-jose (v3.5.0)
Reporter: Nothern131 (AI-assisted automated security audit)
Date: 2026-08-16

Summary

Severity Vulnerability File Confirmed
HIGH RSA JWK parameter validation missing jose/backends/cryptography_backend.py Verified
MEDIUM RSA_OAEP uses deprecated SHA-1 jose/backends/cryptography_backend.py:209 Verified
MEDIUM algorithms=None skips algorithm check jose/jws.py:257 Verified
LOW Unrestricted JWS token size (DoS) jose/constants.py Verified

HIGH: RSA JWK Parameter Validation Missing (CVSS 7.5)

File: https://github.com/mpdavis/python-jose/blob/main/jose/backends/cryptography_backend.py

The CryptographyRSAKey._process_jwk() method accepts JWK dictionaries without validating key parameters:

def _process_jwk(self, jwk_dict):
    if not jwk_dict.get("kty") == "RSA":
        raise JWKError(...)
    e = base64_to_long(jwk_dict.get("e", 256))  # Default e=256 is invalid!
    n = base64_to_long(jwk_dict.get("n"))
    public = rsa.RSAPublicNumbers(e, n)
    # No validation of n bit length, e value, or weak key detection

Issues:

  1. No minimum modulus size checkn can be arbitrarily small (e.g., 512-bit), trivially factorable
  2. Invalid default exponente defaults to 256 when not provided (should be 65537)
  3. No weak key detection — Fermat factorization, small-exponent attacks not prevented
  4. No exponent validatione must satisfy gcd(e, φ(n)) = 1

Impact: An attacker who controls a JWK Set endpoint (or can inject JWKs through kid lookup) can provide weak RSA keys. Applications using these keys for JWT verification would be vulnerable to key recovery attacks.

Fix: Add key size validation (minimum 2048 bits) and exponent validation:

e = base64_to_long(jwk_dict.get("e", 65537))
n = base64_to_long(jwk_dict.get("n"))
if n.bit_length() < 2048:
    raise JWKError("RSA modulus too small")
if e < 3 or e % 2 == 0:
    raise JWKError("Invalid RSA exponent")
public = rsa.RSAPublicNumbers(e, n)

MEDIUM: RSA_OAEP Uses SHA-1 (CVSS 5.3)

File: https://github.com/mpdavis/python-jose/blob/main/jose/backends/cryptography_backend.py#L209

RSA_OAEP = padding.OAEP(padding.MGF1(hashes.SHA1()), hashes.SHA1(), None)

SHA-1 is cryptographically broken (collisions demonstrated since 2017). RSA-OAEP is deprecated in favor of RSA-OAEP-256. This definition still exists and could be used if an application explicitly requests it.

Fix: Deprecate or remove RSA_OAEP (SHA-1), or add a deprecation warning.


MEDIUM: algorithms=None Skips Algorithm Check (CVSS 5.0)

File: https://github.com/mpdavis/python-jose/blob/main/jose/jws.py#L257

def _verify_signature(signing_input, header, signature, key="", algorithms=None):
    alg = header.get("alg")
    if not alg:
        raise JWSError("No algorithm was specified in the JWS header.")
    if algorithms is not None and alg not in algorithms:  # Skipped when algorithms=None
        raise JWSError("The specified alg value is not allowed")

When algorithms=None (the default in jwt.decode()), the algorithm whitelist check is completely bypassed. While the current code prevents alg=none by excluding it from SUPPORTED, this is a design flaw — it relies on the algorithm list being exhaustive rather than enforcing positive restrictions.

Fix: Require algorithms to be a non-None iterable:

if algorithms is None:
    raise JWSError("algorithms parameter is required")
if alg not in algorithms:
    raise JWSError("The specified alg value is not allowed")

LOW: Unrestricted JWS Token Size (CVSS 3.7)

File: https://github.com/mpdavis/python-jose/blob/main/jose/constants.py

JWE_SIZE_LIMIT = 250 * 1024 (250KB) exists but there is no equivalent limit for JWS tokens. A maliciously large JWT could cause memory exhaustion.

Fix: Add JWS_SIZE_LIMIT and enforce it during parsing.


Generated by AI Bug Bounty automated hunting tool:Reporter: Nothern131

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions