Integrity Failures in Fastapi with Firestore
Integrity Failures in Fastapi with Firestore — how this specific combination creates or exposes the vulnerability
Integrity failures occur when an API allows unauthorized modification, deletion, or corruption of data. In a Fastapi application using Google Cloud Firestore as the backend, these failures often arise from insufficient server-side validation of document updates combined with overly permissive Firestore security rules. Firestore’s flexible data model and rule language can inadvertently permit clients to alter fields they should not touch, especially when update operations do not explicitly whitelist allowed fields.
Consider a Fastapi endpoint that accepts user input to update a Firestore document without validating each field against a strict schema. If the endpoint merges the incoming JSON into an update operation (e.g., using set(data, merge=True)), a client may inject unexpected keys that modify sensitive attributes such as role flags, permissions, or financial balances. Because Firestore applies updates at the field level, missing field-level authorization in rules can enable privilege escalation or unauthorized changes to critical resources.
Another common pattern is using client-supplied document IDs or paths. If a Fastapi route constructs a Firestore document reference from user input without strict validation, an attacker can traverse to unrelated collections or documents, leading to Insecure Direct Object References (IDOR) that compromise integrity. For example, a route like /users/{user_id}/profile that directly uses user_id to build db.collection("users").document(user_id) may allow an attacker to modify another user’s profile by guessing or iterating IDs.
The combination of Fastapi’s loose request parsing and Firestore’s permissive update semantics amplifies risk. Without server-side enforcement of data integrity — such as explicit field masks, transaction-based checks, or strict security rules that limit who can write which fields — an attacker can inject malicious values, reorder inventory counts, or escalate their own access. This maps to common vulnerability classes like BOLA/IDOR and BFLA/Privilege Escalation within the OWASP API Top 10 and can violate compliance frameworks that require strict data integrity controls.
Firestore-Specific Remediation in Fastapi — concrete code fixes
To protect integrity when using Fastapi with Firestore, enforce strict validation on the server and design security rules that follow least-privilege principles. Below are concrete code examples that demonstrate safe practices.
First, define a Pydantic model that explicitly lists allowed fields for updates and use it to validate incoming requests. This ensures only intended fields are processed, preventing injection of malicious keys.
from fastapi import Fastapi, HTTPException, Depends
from pydantic import BaseModel, Field
from typing import Optional
import google.cloud.firestore
app = Fastapi()
db = google.cloud.firestore.Client()
class ProfileUpdate(BaseModel):
display_name: Optional[str] = Field(None, min_length=1, max_length=100)
email: Optional[str] = Field(None, regex=r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$")
# Do not include sensitive fields like role, is_admin, balance
@app.patch("/profiles/{doc_id}")
def update_profile(doc_id: str, update: ProfileUpdate):
# Use a transaction to read and conditionally update, ensuring integrity
doc_ref = db.collection("profiles").document(doc_id)
try:
doc = doc_ref.get()
if not doc.exists:
raise HTTPException(status_code=404, detail="Document not found")
# Explicitly map only allowed fields
updates = {k: v for k, v in update.dict(exclude_unset=True).items() if v is not None}
if updates:
doc_ref.update(updates)
return {"status": "updated"}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
Second, enforce field-level security rules in Firestore to restrict writes to authorized fields and identities. Rules should validate that updates do not modify protected fields and that the requesting user matches the document owner.
rules_version = "2";
service cloud.firestore {
match /databases/{database}/documents {
match /profiles/{profileId} {
allow read: if request.auth != null;
allow update: if request.auth != null
&& request.auth.uid == profileId
&& request.resource.data.diff(resource.data).affectedKeys()
.hasOnly(["display_name", "email"])
&& !request.resource.data.diff(resource.data).affectedKeys().hasAny(["role", "is_admin", "balance"]);
}
}
}
Third, when designing Fastapi routes, avoid using raw user input to construct document paths. Instead, map authenticated user identifiers to canonical document references server-side. This prevents IDOR via manipulated IDs.
@app.get("/users/me/profile")
def get_my_profile(auth: dict = Depends(get_current_user)):
# Derive document ID from server-side auth, not client input
doc_ref = db.collection("profiles").document(auth["uid"])
doc = doc_ref.get()
if not doc.exists:
raise HTTPException(status_code=404, detail="Profile not found")
return doc.to_dict()
These practices — strict input validation, transaction-safe updates, and tightly scoped Firestore rules — reduce the surface for integrity failures. They address BOLA/IDOR by ensuring users can only modify their own documents with permitted fields, and they counter BFLA/Privilege Escalation by blocking unauthorized changes to sensitive attributes. Because middleBrick scans unauthenticated attack surfaces, it can surface misconfigured rules and missing server-side checks as high-severity findings, emphasizing the need for these controls.