Pii Leakage in Fastapi with Jwt Tokens
Pii Leakage in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability
In a FastAPI application that uses JWT tokens for authentication, PII leakage often occurs when token contents or related request/response flows expose sensitive information beyond what the token is intended to convey. JWTs typically carry claims such as user identifier, role, and scope, but developers may inadvertently include PII like email, phone number, or internal user IDs within the token payload or in logged/debug output tied to token handling.
Because JWTs are often stored in browser storage or passed in URLs, any PII embedded in the token can be read by client-side scripts or exposed via browser history. A common anti-pattern is placing a user email or full name inside the JWT payload to avoid extra database lookups; this couples identity data to the token and increases the blast radius if the token is leaked through XSS or insecure storage.
Another leakage vector arises when FastAPI endpoints return token metadata or introspection responses that include user details. For example, an endpoint that echoes the decoded token or merges token claims with database records may serialize PII into JSON responses. If these responses are cached by intermediaries or logged in application telemetry, PII can persist in logs or third-party systems outside the intended access boundaries.
Additionally, token refresh flows can contribute to exposure. If a FastAPI implementation issues new tokens with the same payload including PII, and those tokens are transmitted over non-HTTPS channels or with weak cipher configurations, the data can be intercepted. Even with HTTPS, verbose tokens increase the size of headers, which may be logged in server access logs or API gateways, creating a persistent record of PII tied to authentication events.
From an API security scanning perspective, tools like middleBrick assess whether PII appears in token-related responses, whether tokens are transmitted over unauthenticated endpoints, and whether token introspection or error messages reveal sensitive user data. Findings typically highlight missing data minimization in token payloads, insecure transmission practices, and insufficient controls around logging and error handling, all of which can lead to PII leakage in JWT-based FastAPI systems.
Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes
Remediation centers on minimizing token payload, enforcing secure transmission, and hardening logging and error handling. Keep JWT claims to a minimal set of authorization-relevant values such as user ID, role, and scope, and avoid embedding direct identifiers or contact information.
Secure JWT creation and validation in FastAPI
Use the python-jose library with strong algorithms like RS256 and validate all incoming tokens rigorously. Configure token expiration short to reduce exposure windows, and avoid including PII in the payload.
from datetime import datetime, timedelta
from jose import jwt, JWTError
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
SECRET_KEY = "your-secure-secret-or-private-key"
ALGORITHM = "RS256"
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
def create_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire, "iat": datetime.utcnow()})
# Only include minimal claims; avoid PII like email or name here
encoded = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
return encoded
def decode_token(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id: str = payload.get("sub")
if user_id is None:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
return user_id
except JWTError:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid authentication credentials",
headers={"WWW-Authenticate": "Bearer"},
)
Mitigate logging and introspection risks
Ensure that token validation errors do not echo the token or its claims. Avoid logging raw tokens or decoded payloads. Use structured logging that redacts sensitive fields, and configure access and error logs to exclude Authorization headers.
import logging
logger = logging.getLogger("api")
# Bad: logger.info(f"Token: {token}")
# Good: logger.info("Token validated for user_id=%s", user_id)
Transport and storage safeguards
Enforce HTTPS site-wide and set the Secure and HttpOnly flags on cookies if storing tokens in browsers. For SPAs, prefer short-lived access tokens with refresh token rotation stored in secure, same-site cookies to mitigate XSS and token leakage via browser history.
Token refresh with minimal claims
When issuing refresh tokens, keep the payload minimal and store server-side mappings securely. Do not embed PII in refresh tokens, and rotate signing keys periodically to limit the impact of a compromised key.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |