HIGH xss cross site scriptingfastapijwt tokens

Xss Cross Site Scripting in Fastapi with Jwt Tokens

Xss Cross Site Scripting in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

Cross-site scripting (XSS) in a FastAPI application that uses JWT tokens typically arises when an API returns data that eventually reaches a browser context without adequate escaping. Even when endpoints are protected by JWT-based authentication, improper handling of user-controlled data can introduce injection points. For example, an endpoint might embed user-controlled values into JSON responses that a single-page application consumes and then render via innerHTML or unsafe template interpolation. In such cases, the presence of a valid JWT does not mitigate XSS; it only confirms the request’s authenticity, while malicious payloads execute in the victim’s browser with the victim’s permissions.

Another common pattern is token leakage in URLs or logs. If a FastAPI route includes the JWT in query parameters (e.g., for sharing or tracking), and the response reflects the token or related data without sanitization, an attacker can craft a link that triggers XSS when the victim visits it. Compounded by misconfigured CORS or overly permissive origins, this can allow injected scripts to make authenticated requests on behalf of the user. While the JWT validates identity, it does not validate or sanitize content, so any reflected or stored data must be escaped for the target context.

Consider a FastAPI endpoint that returns user-controlled fields within a JSON structure consumed by JavaScript:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str

@app.get("/items/{item_id}")
def read_item(item_id: int, user_token: str = None):
    # user_token is extracted from Authorization header
    return {"item_id": item_id, "name": "" + item_id + "", "description": "Hello"}

If the name field originates from user input and the response is rendered in a vulnerable frontend, an attacker can supply name as <script>stealCookies()</script>. Even with JWT authentication present, the reflected script executes in the browser. This illustrates why JWT tokens must be treated strictly as credentials, while output encoding and strict content-type headers remain essential for XSS prevention.

Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes

Remediation focuses on strict separation of authentication and output safety. JWT tokens should only be used to establish identity, never to decide how data is encoded for different contexts. Always enforce strong Content-Security-Policy headers, validate and sanitize all user-supplied data, and use secure default headers.

In FastAPI, configure security headers and response encoding explicitly. For example, set headers to prevent MIME-sniffing and enforce JSON content types to reduce XSS surface:

from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import JSONResponse
import json

app = FastAPI()

# Restrict origins instead of using wildcard
app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://trusted.example.com"],
    allow_credentials=True,
    allow_methods=["GET"],
    allow_headers=["Authorization", "Content-Type"],
)

class SecurityHeadersMiddleware(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        response = await call_next(request)
        response.headers["Content-Security-Policy"] = "default-src 'self'; script-src 'self' https://trusted-cdn.example.com; object-src 'none'"
        response.headers["X-Content-Type-Options"] = "nosniff"
        response.headers["X-Frame-Options"] = "DENY"
        return response

app.add_middleware(SecurityHeadersMiddleware)

When returning user data, ensure proper escaping for the intended context. For JSON responses, rely on strict schemas and avoid embedding HTML. If HTML must be rendered, encode on the client using a well-maintained library and never use innerHTML. Here’s a safer endpoint example that validates input and avoids reflection of sensitive tokens:

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel, validator
import re

app = FastAPI()
security_scheme = HTTPBearer()

class ItemResponse(BaseModel):
    item_id: int
    name: str
    description: str

    @validator("name")
    def validate_name(cls, v):
        # Basic example: allow only alphanumeric, spaces, and a few safe chars
        if not re.match(r"^[A-Za-z0-9 _\-]*$", v):
            raise ValueError("Name contains invalid characters")
        return v

def get_current_token(credentials: HTTPAuthorizationCredentials = Depends(security_scheme)):
    # Perform JWT validation and return payload or raise
    if not credentials.credentials or not credentials.credentials.startswith("Bearer "):
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid authentication")
    token = credentials.credentials.split(" ")[1]
    # Decode and verify token using your preferred library
    return token

@app.get("/items/{item_id}", response_model=ItemResponse)
def read_item(
    item_id: int,
    token: str = Depends(get_current_token),
):
    # Use validated item_id and safe name construction
    name = f"Item-{item_id}"
    return ItemResponse(item_id=item_id, name=name, description="Hello")

These patterns ensure JWT tokens are handled as credentials only, while output contexts are secured through validation, safe defaults, and context-aware encoding.

Related CWEs: inputValidation

CWE IDNameSeverity
CWE-20Improper Input Validation HIGH
CWE-22Path Traversal HIGH
CWE-74Injection CRITICAL
CWE-77Command Injection CRITICAL
CWE-78OS Command Injection CRITICAL
CWE-79Cross-site Scripting (XSS) HIGH
CWE-89SQL Injection CRITICAL
CWE-90LDAP Injection HIGH
CWE-91XML Injection HIGH
CWE-94Code Injection CRITICAL

Frequently Asked Questions

Does a valid JWT token prevent XSS in FastAPI APIs?
No. JWT tokens authenticate requests but do not prevent XSS. Output encoding, Content-Security-Policy, and input validation remain essential regardless of authentication.
Should I include JWTs in URLs or logs to simplify debugging?
Avoid including JWTs in URLs or logs. This can lead to token leakage via referrers, logs, or browser history, increasing exposure to XSS and other token theft vectors.