HIGH dns rebindingfastapijwt tokens

Dns Rebinding in Fastapi with Jwt Tokens

Dns Rebinding in Fastapi with Jwt Tokens — how this specific combination creates or exposes the vulnerability

DNS rebinding is a network-based attack where an attacker tricks a victim’s browser into resolving a domain name to an IP address that changes over the course of a session, often from a public internet address to a private one (e.g., 127.0.0.1). When this occurs in an application using FastAPI with JWT-based authentication, the combination can bypass intended access controls and expose internal services.

Consider a FastAPI service that validates a JWT access token on each request and uses the decoded claims to enforce authorization. If the application relies solely on the presence and validity of a JWT (e.g., checking signature and exp) without additional network-level or session binding, an attacker may use a malicious webpage to make authenticated requests to the API on the user’s behalf. Because the browser automatically includes cookies and authentication headers for the target domain, the FastAPI endpoint may process these requests with the privileges of the authenticated user.

During a scan, middleBrick tests this attack surface by probing endpoints that accept JWT tokens and checking whether requests originating from manipulated DNS resolutions are accepted. If FastAPI routes trust the JWT but do not validate the request origin, enforce strict host checks, or bind tokens to client context (such as IP or TLS channel), the scan may identify BOLA/IDOR or Property Authorization findings. For example, an endpoint like /api/users/me that returns user details based solely on a valid JWT could inadvertently expose one user’s data to another if the request is proxied through a rebinding scenario where internal route handling does not re-validate network context.

In a real scan, middleBrick’s unauthenticated checks simulate a browser-like scenario where DNS resolution changes mid-session and requests carry valid JWT tokens. The tool examines whether authorization logic is coupled with network or request metadata. Because JWTs are often stored in headers (e.g., Authorization: Bearer), they are not automatically protected against rebinding unless the server implements additional constraints. Findings may include insecure CORS configurations, missing origin validation, or routes that process sensitive operations without re-authorizing the request context.

To detect this class of issue, middleBrick runs multiple security checks in parallel, including Authentication, BOLA/IDOR, and Property Authorization. These checks do not assume internal knowledge of the application architecture; instead, they rely on runtime behavior to determine whether a valid JWT can be used in a rebinding scenario to access resources outside the intended scope. The scanner highlights the need to treat JWT validation as one layer in a defense-in-depth strategy rather than a complete access control mechanism.

Jwt Tokens-Specific Remediation in Fastapi — concrete code fixes

Remediation focuses on ensuring that JWT validation is combined with explicit network and request context checks. Below are concrete code examples for a FastAPI application that mitigate DNS rebinding risks while preserving proper authentication and authorization.

First, configure CORS to restrict origins explicitly. Do not allow wildcards when credentials are involved:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["https://your-trusted-domain.com"],
    allow_credentials=True,
    allow_methods=["GET", "POST"],
    allow_headers=["Authorization", "Content-Type"],
)

Second, implement a utility to validate the request host against a whitelist. This prevents requests rebound to internal IPs from being trusted:

from fastapi import Request, HTTPException
import socket

TRUSTED_HOSTS = {"api.yourcompany.com", "app.yourcompany.com"}

def validate_request_host(request: Request) -> None:
    host = request.headers.get("host", "")
    # Normalize host: strip port if present
    hostname = host.split(":")[0]
    # Resolve and ensure it resolves to a permitted domain or IP range
    try:
        resolved = socket.gethostbyname(hostname)
        if resolved.startswith("127.") or resolved.startswith("10.") or resolved.startswith("192.168."):
            raise HTTPException(status_code=403, detail="Forbidden internal access")
    except socket.error:
        raise HTTPException(status_code=400, detail="Invalid host")
    if hostname not in TRUSTED_HOSTS:
        raise HTTPException(status_code=403, detail="Host not allowed")

Third, enrich your JWT validation to include checks on the aud (audience) and iss (issuer) claims, and bind authorization to the request context. Here is an example using python-jose and fastapi:

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

security_scheme = HTTPBearer()

def decode_jwt_token(credentials: HTTPAuthorizationCredentials = Depends(security_scheme)):
    token = credentials.credentials
    try:
        payload = jwt.decode(token, "your-secret-key", algorithms=["HS256"], audience="your-api-audience", issuer="your-issuer")
        return payload
    except JWTError:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid authentication credentials",
            headers={"WWW-Authenticate": "Bearer"},
        )

def get_current_user(payload: dict = Depends(decode_jwt_token)):
    # Here you can also cross-check payload["sub"] with a user store and ensure request aligns with user context
    return payload

Finally, combine these measures in a route to ensure that each request is authenticated, authorized, and originates from a trusted context:

@app.get("/api/users/me")
async def read_current_user(
    request: Request,
    user: dict = Depends(get_current_user)
):
    validate_request_host(request)
    # Proceed only if host validation passes
    return {"user_id": user.get("sub"), "username": user.get("username")}

These steps ensure that JWT tokens are validated with proper audience and issuer constraints, and that requests are bound to trusted hosts and network contexts, reducing the risk of DNS rebinding compromising authenticated endpoints.

Frequently Asked Questions

Can DNS rebinding bypass JWT protection if CORS is misconfigured?
Yes. If CORS allows untrusted origins or wildcard origins with credentials, a malicious site can make authenticated requests using the victim’s JWT. Always restrict CORS to known origins and avoid wildcard origins when credentials are enabled.
Does middleBrick test for DNS rebinding in authenticated endpoints?
middleBrick tests unauthenticated attack surfaces but can identify endpoints where valid JWT tokens are accepted without host or origin validation. Findings such as BOLA/IDOR or Property Authorization may indicate exposure that could be leveraged in a rebinding scenario.