Bleichenbacher Attack in Fastapi with Jwt Tokens
Bleichenbacher Attack in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
A Bleichenbacher attack is a cryptographic padding oracle attack that was originally described against PKCS#1 v1.5–encrypted RSA data. In the context of FastAPI applications that use JWT tokens, the attack surface arises when a server performs asymmetric cryptographic operations (e.g., RSA verification) and reveals distinguishable behavior based on whether a provided token signature or padding is valid. While JWTs are commonly signed using algorithms such as HS256 or RS256, the risk materializes when an endpoint accepts a JWT, passes it to an RSA verification routine, and the routine’s error handling or timing characteristics differ between valid and invalid padding. An attacker can send many signed tokens with slightly modified ciphertexts and observe differences in responses (HTTP status codes, timing, error messages), gradually recovering the private key or forging tokens without knowing the original secret or private key.
In FastAPI, this can occur when using libraries such as PyJWT with an RSA public key and verifying tokens with algorithms like RS256. If the verification endpoint does not use constant-time checks and provides verbose errors (e.g., bad padding vs. invalid signature), it effectively acts as a padding oracle. For example, an endpoint that decodes and verifies a JWT and returns distinct messages for malformed tokens versus invalid signatures can be probed systematically. The unauthenticated attack surface that middleBrick scans highlights such endpoints because they expose JWT verification behavior without requiring authentication. Attackers can automate requests with tokens that have valid structure but invalid signatures, iteratively learning about the private key or forging tokens. This is especially concerning when tokens are issued with weak key lengths or when the server inadvertently exposes stack traces or internal errors that assist the oracle.
middleBrick’s checks include input validation and authentication testing, which can surface endpoints that process untrusted JWT inputs and may leak verification behavior. An OpenAPI/Swagger spec analysis (with full $ref resolution) combined with runtime testing helps identify routes that accept JWTs and whether they exhibit behaviors consistent with a potential Bleichenbacher-style oracle. Since the scanner operates without credentials, it focuses on what an unauthenticated attacker can observe: inconsistent responses, timing differences inferred from status codes, and endpoints that perform cryptographic verification on client-supplied tokens. Remediation focuses on removing oracle behavior, ensuring constant-time verification, and avoiding exposing low-level cryptographic errors to the client.
Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes
To mitigate Bleichenbacher-style attacks in FastAPI when using JWT tokens, ensure verification is performed in constant time and that error paths do not distinguish between padding failures and other invalid inputs. Use well-maintained libraries and avoid implementing RSA decryption or verification manually. Always catch generic exceptions and return a uniform error response so that no timing or information leak distinguishes a bad padding from an invalid signature.
Example secure FastAPI implementation using PyJWT with an RSA public key:
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
import jwt
from jwt import PyJWKClient
from pydantic import BaseModel
import time
app = FastAPI()
# Load JWKS from a trusted, well-secured endpoint
jwks_url = "https://example.com/.well-known/jwks.json"
jwks_client = PyJWKClient(jwks_url)
class TokenRequest(BaseModel):
token: str
@app.post("/verify")
def verify_token(req: TokenRequest):
try:
# Use get_signing_key to select the correct key without leaking info
signing_key = jwks_client.get_signing_key_from_jwt(req.token)
# Decode and verify with explicit algorithms and options
decoded = jwt.decode(
req.token,
key=signing_key.key,
algorithms=["RS256"],
options={"verify_signature": True, "require": ["exp", "iat", "iss"]},
)
return {"valid": True, "payload": decoded}
except jwt.ExpiredSignatureError:
# Return a generic error to avoid distinguishing token validity details
return JSONResponse(
status_code=401,
content={"error": "invalid_token", "error_description": "Token expired or invalid"},
)
except jwt.InvalidTokenError:
# Always return the same status and message regardless of error type
return JSONResponse(
status_code=401,
content={"error": "invalid_token", "error_description": "Token expired or invalid"},
)
except Exception:
# Catch-all to prevent any low-level details from leaking
return JSONResponse(
status_code=401,
content={"error": "invalid_token", "error_description": "Token expired or invalid"},
)
Key practices to prevent Bleichenbacher-style oracle behavior:
- Use constant-time verification: rely on library functions that do not branch on padding validity.
- Never return stack traces or low-level cryptographic errors to the client; always map them to a generic invalid_token response.
- Specify allowed algorithms explicitly to prevent algorithm confusion attacks (e.g., do not accept none or HS256 when expecting RS256).
- Validate standard claims (exp, nbf, iss, aud) uniformly and reject tokens with missing or malformed claims in the same way as invalid signatures.
- If you use asymmetric keys, fetch JWKS from a trusted, rate-limited source and cache keys securely; avoid dynamic key selection that depends on unverified token content.
middleBrick’s scans can help surface endpoints that accept JWTs and check whether they exhibit timing-sensitive behavior or verbose error messages. Its OpenAPI/Swagger analysis resolves $ref chains to inspect schemas and security schemes, while runtime probes test input validation and authentication patterns to highlight risks associated with JWT handling.