HIGH auth bypassfastapi

Auth Bypass in Fastapi

How Auth Bypass Manifests in Fastapi

Authentication bypass in Fastapi applications often stems from subtle implementation mistakes that can have severe consequences. One common pattern involves improper use of dependency injection. Consider this vulnerable Fastapi route:

from fastapi import FastAPI, Depends
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/token")

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

app = FastAPI()

async def get_current_user(token: str = Depends(oauth2_scheme)):
    # Implementation that might not raise an exception on failure
    return None

@app.post("/items/")
async def create_item(item: Item, current_user: Any = Depends(get_current_user)):
    return {"item": item.dict(), "user": current_user}

The vulnerability here is that the get_current_user dependency doesn't properly handle authentication failures. If it returns None instead of raising an HTTPException, Fastapi will still process the request with an unauthenticated user.

Another Fastapi-specific auth bypass pattern involves misconfigured CORS settings. Fastapi's CORS middleware can be improperly configured:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

This configuration allows any origin to make credentialed requests, potentially enabling cross-site request forgery (CSRF) attacks that bypass authentication checks.

Fastapi's path parameter handling can also introduce auth bypass vulnerabilities. Consider this route:

@app.get("/users/me")
async def read_user_me(current_user: User = Depends(get_current_user)):
    return current_user

@app.get("/users/{user_id}")
async def read_user(user_id: int):
    # No authentication dependency
    user = get_user_by_id(user_id)
    return user

If the /users/me endpoint is protected but /users/{user_id} isn't, an attacker can enumerate user IDs and bypass authentication entirely.

Fastapi-Specific Detection

Detecting authentication bypass vulnerabilities in Fastapi requires both static analysis and runtime testing. For static analysis, look for these Fastapi-specific patterns:

Missing authentication dependencies in route handlers:

# Vulnerable - no Depends() for auth
@app.get("/admin/")
async def admin_dashboard():
    return admin_panel

# Secure - proper dependency injection
@app.get("/admin/")
async def admin_dashboard(current_user: User = Depends(get_current_user)):
    return admin_panel

Improper exception handling in dependencies:

# Vulnerable - doesn't raise on auth failure
async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_token(token)
    return user  # Returns None on failure

# Secure - raises HTTPException on failure
async def get_current_user(token: str = Depends(oauth2_scheme)):
    user = verify_token(token)
    if user is None:
        raise HTTPException(status_code=401, detail="Unauthorized")
    return user

For runtime detection, middleBrick's black-box scanning approach is particularly effective for Fastapi applications. The scanner tests unauthenticated endpoints by sending requests to your Fastapi routes and analyzing responses. For authentication bypass detection, middleBrick:

  • Attempts to access protected endpoints without credentials
  • Tests for IDOR vulnerabilities by modifying user IDs in path parameters
  • Checks for missing authentication dependencies by analyzing route structure
  • Tests CORS configurations for permissive settings

middleBrick's OpenAPI spec analysis is especially valuable for Fastapi since the framework auto-generates OpenAPI specs. The scanner cross-references your spec with actual runtime behavior to identify discrepancies that might indicate auth bypass vulnerabilities.

Fastapi-Specific Remediation

Securing Fastapi applications against authentication bypass requires implementing proper authentication patterns. Here are Fastapi-specific remediation techniques:

1. Use Fastapi's dependency injection system correctly:

from fastapi import HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id = payload.get("sub")
        if user_id is None:
            raise credentials_exception
        
        user = get_user_by_id(user_id)
        if user is None:
            raise credentials_exception
        
        return user
    except JWTError:
        raise credentials_exception

2. Create reusable authentication dependencies:

async def get_current_active_user(current_user: User = Depends(get_current_user)):
    if current_user.disabled:
        raise HTTPException(status_code=400, detail="Inactive user")
    return current_user

async def get_current_active_superuser(current_user: User = Depends(get_current_active_user)):
    if current_user.role != "superuser":
        raise HTTPException(status_code=400, detail="The user doesn't have enough privileges")
    return current_user

3. Use Fastapi's built-in security features:

from fastapi import Depends, HTTPException, status
from fastapi.security import HTTPBearer

bearer_scheme = HTTPBearer()

def verify_token(token: str = Depends(bearer_scheme)):
    try:
        payload = jwt.decode(token.credentials, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )

4. Implement proper CORS configuration:

from fastapi.middleware.cors import CORSMiddleware

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://yourdomain.com"],  # Specific origins only
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Authorization", "Content-Type"],
)

5. Use middleware for global authentication checks:

from fastapi import Request, Response

async def auth_middleware(request: Request, call_next):
    if not is_authenticated(request):
        return JSONResponse(
            status_code=401,
            content={"detail": "Not authenticated"},
        )
    
    response = await call_next(request)
    return response

app.add_middleware(auth_middleware)

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How can I test my Fastapi application for authentication bypass vulnerabilities?
You can use middleBrick's black-box scanning approach, which tests your Fastapi endpoints without requiring credentials or access to source code. The scanner attempts to access protected endpoints without authentication, tests for IDOR vulnerabilities by modifying user IDs in path parameters, and analyzes your OpenAPI spec for authentication gaps. Simply provide your Fastapi application's URL and middleBrick will run 12 security checks including authentication bypass detection in 5-15 seconds.
What's the difference between Fastapi's Depends() and middleware for authentication?
Depends() provides route-specific dependency injection, allowing you to apply authentication only where needed and pass the authenticated user to your endpoint. Middleware applies globally to all routes, which is useful for applications where all endpoints require authentication. For Fastapi applications with mixed public/private endpoints, Depends() is generally preferred as it provides more granular control. Middleware is better for APIs where authentication is mandatory for all routes.