Ssrf Server Side in Fastapi with Firestore
Ssrf Server Side in Fastapi with Firestore — how this specific combination creates or exposes the vulnerability
Server-side request forgery (SSRF) in a FastAPI application that uses Google Cloud Firestore can occur when the app constructs HTTP requests based on attacker-controlled input and then uses those requests to interact with Firestore or other internal services. For example, if an endpoint accepts a Firestore document path or a URL and passes it to an HTTP client without validation, an attacker may force the server to reach internal metadata services or internal APIs. The Firestore client libraries themselves do not typically introduce SSRF, but the surrounding code that combines external input, outbound HTTP calls, and Firestore operations can amplify the impact.
Consider a scenario where FastAPI dynamically builds a Firestore document reference from user input and also makes an outbound HTTP call (for example, to fetch remote configuration or to call another service). If the URL for the outbound call is derived from user-supplied data and the Firestore reference is also driven by unchecked input, an attacker may coerce the server into reading from or writing to unintended Firestore paths, or into reaching internal endpoints that are not exposed publicly. This can lead to unauthorized data access, data modification, or pivoting to internal services that would otherwise be unreachable from the internet.
Common patterns that increase risk include using user input to form query parameters for Firestore gets or queries, and combining that with HTTP requests whose host or port is supplied by the user. For instance, an endpoint that accepts a document ID and a webhook URL, then uses the ID to fetch a Firestore document and the URL to POST data, can become an SSRF vector if neither input is strictly validated. The Firestore operations may succeed, but the side-channel HTTP call can expose sensitive metadata or enable further internal probing.
Because FastAPI applications often run with service account credentials that permit Firestore access, an SSRF vulnerability can allow an attacker to leverage those permissions beyond the intended scope. The presence of Firestore does not cause SSRF, but it can provide a high-value target if the server is tricked into accessing internal resources. Effective mitigation in this context requires strict allowlisting of expected destinations for outbound requests, robust input validation for any document identifiers or query parameters used with Firestore, and network-level controls that limit egress from the application environment.
Firestore-Specific Remediation in Fastapi — concrete code fixes
Remediation centers on validating and constraining all inputs that affect Firestore paths and outbound HTTP calls. Do not concatenate user input directly into document references or URLs. Instead, use strict allowlists, canonical resource identifiers, and server-side configuration for external endpoints.
Secure Firestore document access
Use hardcoded document paths or map validated identifiers to known document keys. Avoid using raw user input to build document references.
from fastapi import FastAPI, HTTPException
from google.cloud import firestore
import re
app = FastAPI()
db = firestore.Client()
# Safe: map a validated integer ID to a known collection and document
@app.get("/documents/{doc_id}")
def get_document(doc_id: int):
if not (1000 <= doc_id <= 9999):
raise HTTPException(status_code=400, detail="Invalid document identifier")
doc_ref = db.collection("approved_collection").document(str(doc_id))
snapshot = doc_ref.get()
if not snapshot.exists:
raise HTTPException(status_code=404, detail="Document not found")
return {"id": doc_ref.id, "data": snapshot.to_dict()}
If you must accept a document name, enforce a strict pattern and use it only within a predefined collection.
import re
from fastapi import FastAPI, HTTPException
from google.cloud import firestore
app = FastAPI()
db = firestore.Client()
PATTERN = re.compile(r"^[a-z0-9_-]{1,64}\Z")
@app.get("/items/{item_name}")
def get_item(item_name: str):
if not PATTERN.match(item_name):
raise HTTPException(status_code=400, detail="Invalid item name")
doc_ref = db.collection("items").document(item_name)
snapshot = doc_ref.get()
if not snapshot.exists:
raise HTTPException(status_code=404, detail="Item not found")
return {"id": doc_ref.id, "data": snapshot.to_dict()}
Safe outbound HTTP calls
Do not allow user input to control the host or port of outbound HTTP requests. Use a fixed, server-side configured endpoint and validate any payloads before sending.
from fastapi import FastAPI, HTTPException, Body
from starlette.status import ST_UNPROCESSABLE_ENTITY
import httpx
app = FastAPI()
# Safe: destination is fixed; only the payload is controlled by the caller
@app.post("/submit")
async def submit_data(payload: dict = Body(...)):
destination = "https://fixed.example.com/webhook"
async with httpx.AsyncClient(timeout=10.0) as client:
try:
resp = await client.post(destination, json=payload, headers={"X-API-Key": "your-key"})
resp.raise_for_status()
except httpx.HTTPError as e:
raise HTTPException(status_code=502, detail="Failed to reach fixed endpoint")
return {"status": "ok"}
If you must call multiple preapproved endpoints, map an allowed key to a URL and reject anything not in the map.
from fastapi import FastAPI, HTTPException
import httpx
app = FastAPI()
ENDPOINTS = {
"config": "https://config.example.com/v1/settings",
"status": "https://status.example.com/v1/health",
}
@app.get("/fetch/{key}")
async def fetch(key: str):
if key not in ENDPOINTS:
raise HTTPException(status_code=400, detail="Endpoint not allowed")
async with httpx.AsyncClient(timeout=10.0) as client:
r = await client.get(ENDPOINTS[key])
r.raise_for_status()
return {"data": r.text}
Operational practices
- Restrict outbound traffic from your runtime environment to only necessary destinations.
- Treat Firestore credentials as highly privileged; do not expose Firestore directly to user-controlled network paths.
- Log and monitor requests that involve Firestore document accesses and outbound HTTP calls for anomalies.