<firebase_firestore_security_guide>
<title>FIREBASE / FIRESTORE — ADVERSARIAL TESTING AND EXPLOITATION</title>

<critical>Most impactful findings in Firebase apps arise from weak Firestore/Realtime Database rules, Cloud Storage exposure, callable/onRequest Functions trusting client input, incorrect ID token validation, and over-trusted App Check. Treat every client-supplied field and token as untrusted. Bind subject/tenant on the server, not in the client.</critical>

<scope>
- Firestore (documents/collections, rules, REST/SDK)
- Realtime Database (JSON tree, rules)
- Cloud Storage (rules, signed URLs)
- Auth (ID tokens, custom claims, anonymous/sign-in providers)
- Cloud Functions (onCall/onRequest, triggers)
- Hosting rewrites, CDN/caching, CORS
- App Check (attestation) and its limits
</scope>

<methodology>
1. Extract project config from client (apiKey, authDomain, projectId, appId, storageBucket, messagingSenderId). Identify all used Firebase products.
2. Obtain multiple principals: unauth, anonymous (if enabled), basic user A, user B, and any staff/admin if available. Capture their ID tokens.
3. Build Resource × Action × Principal matrix across Firestore/Realtime/Storage/Functions. Exercise every action via SDK and raw REST (googleapis) to detect parity gaps.
4. Start from list/query paths (where allowed) to seed IDs; then swap document paths, tenants, and user IDs across principals and transports.
</methodology>

<architecture>
- Firestore REST: https://firestore.googleapis.com/v1/projects/<project>/databases/(default)/documents/<path>
- Storage REST: https://storage.googleapis.com/storage/v1/b/<bucket>
- Auth: Google-signed ID tokens (iss accounts.google.com/securetoken.google.com/<project>), aud <project/app-id>; identity is in sub/uid.
- Rules engines: separate for Firestore, Realtime DB, and Storage; Functions bypass rules when using Admin SDK.
</architecture>

<auth_and_tokens>
- ID token verification must enforce issuer, audience (project), signature (Google JWKS), expiration, and optionally App Check binding when used.
- Custom claims are appended by Admin SDK; client-supplied claims are ignored by Auth but may be trusted by app code if copied into docs.
- Pitfalls:
  - Accepting any JWT with valid signature but wrong audience/project.
  - Trusting uid/account IDs from request body instead of context.auth.uid in Functions.
  - Mixing session cookies and ID tokens without verifying both paths equivalently.
- Tests:
  - Replay tokens across environments/projects; expect strict aud/iss rejection server-side.
  - Call Functions with and without Authorization; verify identical checks on both onCall and onRequest variants.
</auth_and_tokens>

<firestore_rules>
- Rules are not filters: a query must include constraints that make the rule true for all returned documents; otherwise reads fail. Do not rely on client to include where clauses correctly.
- Prefer ownership derived from request.auth.uid and server data, not from client payload fields.
- Common gaps:
  - allow read: if request.auth != null (any user reads all data)
  - allow write: if request.auth != null (mass write)
  - Missing per-field validation (adds isAdmin/role/tenantId fields).
  - Using client-supplied ownerId/orgId instead of enforcing doc.ownerId == request.auth.uid or membership in org.
  - Over-broad list rules on root collections; per-doc checks exist but list still leaks via queries.
- Validation patterns:
  - Restrict writes: request.resource.data.keys().hasOnly([...]) and forbid privilege fields.
  - Enforce ownership: resource.data.ownerId == request.auth.uid && request.resource.data.ownerId == request.auth.uid
  - Org membership: exists(/databases/(default)/documents/orgs/$(org)/members/$(request.auth.uid))
- Tests:
  - Compare results for users A/B on identical queries; diff counts and IDs.
  - Attempt cross-tenant reads: where orgId == otherOrg; try queries without org filter to confirm denial.
  - Write-path: set/patch with foreign ownerId/orgId; attempt to flip privilege flags.
</firestore_rules>

<firestore_queries>
- Enumerate via REST to avoid SDK client-side constraints; try structured and REST filters.
- Probe composite index requirements: UI-driven queries may hide missing rule coverage when indexes are enabled but rules are broad.
- Explore collection group queries (collectionGroup) that may bypass per-collection rules if not mirrored.
- Use startAt/endAt/in/array-contains to probe rule edges and pagination cursors for cross-tenant bleed.
</firestore_queries>

<realtime_database>
- Misconfigured rules frequently expose entire JSON trees. Probe https://<project>.firebaseio.com/.json with and without auth.
- Confirm rules for read/write use auth.uid and granular path checks; avoid .read/.write: true or auth != null at high-level nodes.
- Attempt to write privilege-bearing nodes (roles, org membership) and observe downstream effects (e.g., Cloud Functions triggers).
</realtime_database>

<cloud_storage>
- Rules parallel Firestore but apply to object paths. Common issues:
  - Public reads on sensitive buckets/paths.
  - Signed URLs with long TTL, no content-disposition controls; replayable across tenants.
  - List operations exposed: /o?prefix= enumerates object keys.
- Tests:
  - GET gs:// paths via https endpoints without auth; verify content-type and Content-Disposition: attachment.
  - Generate and reuse signed URLs across accounts and paths; try case/URL-encoding variants.
  - Upload HTML/SVG and verify X-Content-Type-Options: nosniff; check for script execution.
</cloud_storage>

<cloud_functions>
- onCall provides context.auth automatically; onRequest must verify ID tokens explicitly. Admin SDK bypasses rules; all ownership/tenant checks must be enforced in code.
- Common gaps:
  - Trusting client uid/orgId from request body instead of context.auth.
  - Missing aud/iss verification when manually parsing tokens.
  - Over-broad CORS allowing credentialed cross-origin requests; echoing Authorization in responses.
  - Triggers (onCreate/onWrite) granting roles or issuing signed URLs solely based on document content controlled by the client.
- Tests:
  - Call both onCall and equivalent onRequest endpoints with varied tokens and bodies; expect identical decisions.
  - Create crafted docs to trigger privilege-granting functions; verify that server re-derives subject/tenant before acting.
  - Attempt internal fetches (SSRF) via Functions to project/metadata endpoints.
</cloud_functions>

<app_check>
- App Check is not a substitute for authorization. Many apps enable App Check enforcement on client SDKs but do not verify on custom backends.
- Bypasses:
  - Unenforced paths: REST calls directly to googleapis endpoints with ID token succeed regardless of App Check.
  - Mobile reverse engineering: hook client and reuse ID token flows without attestation.
- Tests:
  - Compare SDK vs REST behavior with/without App Check headers; confirm no elevated authorization via App Check alone.
</app_check>

<tenant_isolation>
- Apps often implement multi-tenant data models (orgs/<orgId>/...). Bind tenant from server context (membership doc or custom claim), not from client payload.
- Tests:
  - Vary org header/subdomain/query while keeping token fixed; verify server denies cross-tenant access.
  - Export/report Functions: ensure queries execute under caller scope; signed outputs must encode tenant and short TTL.
</tenant_isolation>

<bypass_techniques>
- Content-type switching: JSON vs form vs multipart to hit alternate code paths in onRequest Functions.
- Parameter/field pollution: duplicate JSON keys; last-one-wins in many parsers; attempt to sneak privilege fields.
- Caching/CDN: Hosting rewrites or proxies that key responses without Authorization or tenant headers.
- Race windows: write then read before background enforcements (e.g., post-write claim synchronizations) complete.
</bypass_techniques>

<blind_channels>
- Firestore: use error shape, document count, and ETag/length to infer existence under partial denial.
- Storage: length/timing differences on signed URL attempts leak validity.
- Functions: constant-time comparisons vs variable messages reveal authorization branches.
</blind_channels>

<tooling_and_automation>
- SDK + REST: httpie/curl + jq for REST; Firebase emulator and Rules Playground for rapid iteration.
- Mobile: apktool/objection/frida to extract config and hook SDK calls; inspect network logs for endpoints and tokens.
- Rules analysis: script rule probes for common patterns (auth != null, missing field validation, list vs get parity).
- Functions: fuzz onRequest endpoints with varied content-types and missing/forged Authorization; verify CORS and token handling.
- Storage: enumerate prefixes; test signed URL generation and reuse patterns.
</tooling_and_automation>

<reviewer_checklist>
- Do Firestore/Realtime/Storage rules derive subject and tenant from auth, not client fields?
- Are list/query rules aligned with per-doc checks (no broad list leaks)?
- Are privilege-bearing fields immutable or server-only (forbidden in writes)?
- Do Functions verify ID tokens (iss/aud/exp/signature) and re-derive identity before acting?
- Are Admin SDK operations scoped by server-side checks (ownership/tenant)?
- Is App Check treated as advisory, not authorization, across all paths?
- Are Hosting/CDN cache keys bound to Authorization/tenant to prevent leaks?
</reviewer_checklist>

<validation>
1. Provide owner vs non-owner Firestore queries showing unauthorized access or metadata leak.
2. Demonstrate Cloud Storage read/write beyond intended scope (public object, signed URL reuse, or list exposure).
3. Show a Function accepting forged/foreign identity (wrong aud/iss) or trusting client uid/orgId.
4. Document minimal reproducible requests with roles/tokens used and observed deltas.
</validation>

<false_positives>
- Public collections/objects documented and intended.
- Rules that correctly enforce per-doc checks with matching query constraints.
- Functions verifying tokens and ignoring client-supplied identifiers.
- App Check enforced but not relied upon for authorization.
</false_positives>

<impact>
- Cross-account and cross-tenant data exposure.
- Unauthorized state changes via Functions or direct writes.
- Exfiltration of PII/PHI and private files from Storage.
- Durable privilege escalation via misused custom claims or triggers.
</impact>

<pro_tips>
1. Treat apiKey as project identifier only; identity must come from verified ID tokens.
2. Start from rules: read them, then prove gaps with diffed owner/non-owner requests.
3. Prefer REST for parity checks; SDKs can mask errors via client-side filters.
4. Hunt privilege fields in docs and forbid them via rules; verify immutability.
5. Probe collectionGroup queries and list rules; many leaks live there.
6. Functions are the authority boundary—enforce subject/tenant there even if rules exist.
7. Keep concise PoCs: one owner vs non-owner request per surface that clearly demonstrates the unauthorized delta.
</pro_tips>

<remember>Authorization must hold at every layer: rules, Functions, and Storage. Bind subject and tenant from verified tokens and server data, never from client payload or UI assumptions. Any gap becomes a cross-account or cross-tenant vulnerability.</remember>
</firebase_firestore_security_guide>
