mcpField
H
hunt-fastapi

hunt-fastapi

github.com/uphiagoSecurity1.3k39 installsUpdated 8w ago
Repository

About hunt-fastapi

hunt-fastapi is a security-testing skill for assessing FastAPI applications, aimed at authorized penetration testers and security reviewers. It focuses on framework-specific risks in dependency-based authorization, Pydantic validation, OpenAPI discovery, middleware, and WebSockets.

Key features

  1. 01Fingerprint FastAPI endpoints
  2. 02Mine OpenAPI schemas for routes
  3. 03Test dependency-injection authorization
  4. 04Check Pydantic coercion and extra fields
  5. 05Assess ASGI middleware and proxy trust
  6. 06Compare WebSocket and REST authentication

Use cases

  1. 01Review an authorized FastAPI penetration test
  2. 02Find undocumented routes in a public OpenAPI schema
  3. 03Check authorization differences across REST and WebSocket endpoints

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/uphiago/recon-skills --skill hunt-fastapi

After installing, type/hunt-fastapiin Claude Code to confirm it loaded.

Details

From the project README

FastAPI Security Hunting

Hunt FastAPI-specific vulnerabilities in dependency injection authorization gaps, Pydantic model coercion and extra field exploitation, OpenAPI schema mining for hidden endpoints, and ASGI middleware bypasses. FastAPI's design — dependency injection for auth, Pydantic for validation, OpenAPI auto-generation — creates unique attack surface distinct from Flask or Django.

When to Use

  • Target uses FastAPI (indicated by /docs, /redoc, /openapi.json, or server: uvicorn).
  • OpenAPI schema is publicly accessible.
  • API uses dependency injection (Depends) for authorization.
  • WebSocket endpoints exist alongside REST API.
  • Application uses Pydantic v1 or v2 for request validation.

Quick Detection

# FastAPI fingerprinting
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/openapi.json" | jq '.info.title' 2>/dev/null
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/docs" -w "%{http_code}\n" -o /dev/null
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/redoc" -w "%{http_code}\n" -o /dev/null

Procedure

Phase 1 — OpenAPI Schema Mining
# Download full schema for endpoint discovery
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/openapi.json" | jq '.paths | keys[]'

# Find hidden endpoints not in docs
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/openapi.json" | jq '.paths | to_entries[] | select(.value.get != null and .value.get.security == []) | .key'

# Discover internal endpoints via path parameter fuzzing
ffuf -u "https://target.com/api/FUZZ" \
  -w /path/to/wordlist.txt \
  -mc 200,401,403 \
  -H "Accept: application/json"
Phase 2 — Dependency Injection Authorization Gaps
# Depends vs Security — check if auth is actually enforced
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/admin/users"     # no auth
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/admin/users" \
  -H "Authorization: Bearer INVALID_TOKEN"         # invalid auth

# Dependency override in path operations
# Some endpoints may inherit Depends from router but override with None
for method in GET POST PUT PATCH DELETE; do
  curl --max-time 30 --connect-timeout 10 -sk -X "$method" "https://target.com/api/users/1" \
    -w "$method — %{http_code}\n" -o /dev/null
done

# Background tasks added via BackgroundTasks may skip auth
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/orders" \
  -H "Content-Type: application/json" \
  -d '{"user_id":"VICTIM_ID","product":"test"}'
Phase 3 — Pydantic Model Exploitation
# Type coercion — string "true" coerced to boolean
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/register" \
  -H "Content-Type: application/json" \
  -d '{"username":"test","is_admin":"true"}'  # string coerced to bool

# Extra fields — Pydantic v1 ignores extra, v2 raises error by default
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/users" \
  -H "Content-Type: application/json" \
  -d '{"username":"test","role":"admin"}'  # extra field may be passed to DB

# Content-type switching
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/api/users" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d 'username=test&role=admin&is_superuser=true'
Phase 4 — ASGI Middleware & Proxy Trust
# ProxyHeaders trust — if behind a proxy, spoof client IP
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/me" \
  -H "X-Forwarded-For: 127.0.0.1" \
  -H "X-Real-IP: 127.0.0.1"

# TrustedHostMiddleware bypass
curl --max-time 30 --connect-timeout 10 -sk "https://target.com/api/health" \
  -H "Host: evil.com"

# CORS middleware — test preflight bypass
curl --max-time 30 --connect-timeout 10 -sk -X OPTIONS "https://target.com/api/users" \
  -H "Origin: https://evil.com" \
  -H "Access-Control-Request-Method: DELETE"
Phase 5 — WebSocket Auth Parity
# FastAPI WebSocket endpoints — auth may differ from REST
# Connect without token
wscat -c "wss://target.com/ws/notifications"

# Connect with minimal scope
wscat -c "wss://target.com/ws/admin" -H "Authorization: Bearer USER_TOKEN"

# Mounted sub-app WebSockets may skip middleware
wscat -c "wss://target.com/subapp/ws"
Phase 6 — GraphQL Mount Authorization Gaps
# GraphQL mounted via starlette-graphene or strawberry-graphql
# May not enforce Depends at GraphQL resolver level
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name } } }"}'

# Mutations may work without auth even when queries require it
curl --max-time 30 --connect-timeout 10 -sk -X POST "https://target.com/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"mutation { deleteUser(id: 1) { success } }"}'

Pitfalls

  • Pydantic v2 model_config with extra='ignore' silently drops unknown fields. Test both Pydantic v1 and v2 behavior.
  • OpenAPI schema may be restricted. If /openapi.json returns 403, try /docs and /redoc which serve the same data.
  • FastAPI Depends with Security is NOT the same as Depends. Security integrates with OpenAPI security schemes — but both can be misconfigured.
  • Uvicorn --proxy-headers must be enabled for IP spoofing to work. Check with X-Forwarded-For — if the server sees your real IP, proxy headers are disabled.

Verification

  1. OpenAPI schema reveals endpoints not documented in the public API docs.
  2. An endpoint with Depends(get_current_user) accepts requests without any Authorization header.
  3. Pydantic type coercion accepts string values for boolean/integer fields and persists them.
  4. WebSocket endpoint accepts connections without session authentication while the REST equivalent requires it.

Related Skills

  • hunt-api-misconfig — Broader API configuration issues including Swagger/OpenAPI exposure.
  • hunt-idor — Object-level authorization gaps in FastAPI path parameters.
  • web-enumeration — Directory and endpoint discovery through OpenAPI schema mining.

Comments

Markdown supported