HIGH hallucination attacksfastapijwt tokens

Hallucination Attacks in Fastapi with Jwt Tokens

Hallucination Attacks in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

In Fastapi applications that rely on JWT tokens for authentication, hallucination attacks occur when an API returns fabricated or misleading data in response to manipulated or low-confidence inputs. This is not a parser or token handling issue directly; it is an authorization and input validation problem that becomes severe when access controls are misaligned with the data returned to the authenticated caller.

When JWT tokens are used, the identity and claims (such as scopes or roles) are typically trusted after signature verification. If the endpoint logic uses those claims to decide what data to return but does not enforce strict ownership or authorization checks (e.g., missing or incorrect BOLA/IDOR checks), an attacker with a valid JWT can request resources belonging to other users and receive responses that either do not match their permissions or hallucinate the existence of other resources. For example, an endpoint like /users/{user_id}/profile might verify the JWT and read the sub claim, but if the code ignores validating that the requested user_id matches the token claims, the API may hallucinate data by returning another user’s profile or indicating success when the resource does not exist for that user.

Additionally, hallucination can appear when an endpoint relies on incomplete query parameters or indirect object references while presenting a confident response. With JWT tokens, the API may assume that because authentication succeeded, the caller is authorized to query any identifier, leading to inconsistent states where the token claims are used to filter data at the application layer rather than enforcing data-level permissions at the database layer. This mismatch can expose sensitive data or allow an attacker to infer the existence of other users or resources, effectively hallucinating information that should remain hidden.

Proper defenses require that Fastapi endpoints validate not only the JWT signature but also enforce strict mapping between token claims and the requested resource identifiers. Each data access path must verify that the subject of the JWT owns or is explicitly authorized to view the target resource, using server-side checks and parameterized queries. Without this, even authenticated requests with valid JWT tokens can participate in hallucination attacks that leak information or misrepresent system state.

Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes

To remediate hallucination risks when using JWT tokens in Fastapi, enforce strict authorization tied to token claims and validate all inputs before using them in database queries. Below are concrete, working examples that combine JWT verification with BOLA/IDOR-safe resource access patterns.

First, ensure JWT authentication is set up with proper token extraction and decoding, and that the decoded claims are used to enforce ownership on every request.

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
import jwt
from typing import Optional

app = FastAPI()
security = HTTPBearer()

SECRET_KEY = "your-secret-key"
ALGORITHM = "HS256"

def decode_jwt(token: str) -> dict:
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.ExpiredSignatureError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Token expired")
    except jwt.InvalidTokenError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid token")

def get_current_subject(credentials: HTTPAuthorizationCredentials = Depends(security)) -> str:
    payload = decode_jwt(credentials.credentials)
    subject: Optional[str] = payload.get("sub")
    if subject is None:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Missing subject in token")
    return subject

Next, create an authorization helper that validates that the requested resource belongs to the requesting subject. This prevents hallucination by ensuring the endpoint only returns data when the subject matches the resource identifier.

from fastapi import Depends
from pydantic import BaseModel

class Profile(BaseModel):
    user_id: str
    name: str
    email: str

# Simulated database lookup function
def fetch_profile_from_db(user_id: str):
    # In real code, this would be a database query parameterized by user_id
    db = {
        "alice": {"user_id": "alice", "name": "Alice", "email": "alice@example.com"},
        "bob": {"user_id": "bob", "name": "Bob", "email": "bob@example.com"}
    }
    return db.get(user_id)

def get_profile_for_subject(requested_user_id: str, subject: str = Depends(get_current_subject)):
    if requested_user_id != subject:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Forbidden: cannot access other user data")
    profile = fetch_profile_from_db(requested_user_id)
    if profile is None:
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Profile not found")
    return Profile(**profile)

Use the helper in your route so that every call validates both the JWT and the resource ownership, eliminating mismatched authorization that could lead to hallucination.

@app.get("/profiles/{user_id}", response_model=Profile)
def read_profile(user_id: str, profile: Profile = Depends(get_profile_for_subject)):
    return profile

For list or search endpoints, apply server-side filtering on the server using the subject instead of trusting client-supplied filters that could hallucinate broader result sets.

from typing import List

class Item(BaseModel):
    id: str
    owner: str
    name: str

def fetch_items_for_owner(owner: str):
    # Simulated database items
    all_items = [
        {"id": "1", "owner": "alice", "name": "Item 1"},
        {"id": "2", "owner": "alice", "name": "Item 2"},
        {"id": "3", "owner": "bob", "name": "Item 3"}
    ]
    return [Item(**item) for item in all_items if item["owner"] == owner]

@app.get("/items", response_model=List[Item])
def list_items(owner: str, subject: str = Depends(get_current_subject)):
    if owner != subject:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Forbidden: cannot list other user items")
    return fetch_items_for_owner(owner)

These patterns ensure that JWT tokens are used strictly for authentication while authorization checks are performed server-side, preventing attackers from hallucinating access to resources they do not own.

Related CWEs: llmSecurity

CWE IDNameSeverity
CWE-754Improper Check for Unusual or Exceptional Conditions MEDIUM

Frequently Asked Questions

Why is matching JWT subject to resource identifiers important to prevent hallucination?
Matching the JWT subject to the resource identifier ensures that an authenticated caller can only access resources they own. Without this check, an API may appear to return valid data while actually hallucinating or exposing other users' resources, leading to information disclosure or false confidence in access control.
Can input validation alone mitigate hallucination risks even if JWT checks are in place?
Input validation is necessary but not sufficient on its own. You must also enforce server-side authorization that ties JWT claims to the requested resource identifiers. Relying only on input validation can leave endpoints that incorrectly trust client-supplied identifiers, allowing hallucination via mismatched ownership checks.