strix/skills/technologies/firebase.md
Security testing for Firebase applications. Focus on Firestore/Realtime Database rules, Cloud Storage exposure, callable/onRequest Functions trusting client input, and incorrect ID token validation.
Data Stores
Authentication
Server-Side
Infrastructure
Endpoints
https://firestore.googleapis.com/v1/projects/<project>/databases/(default)/documents/<path>https://<project>.firebaseio.com/.jsonhttps://storage.googleapis.com/storage/v1/b/<bucket>https://firebasestorage.googleapis.com/v0/b/<bucket>/oCloud Storage has two front doors with different authorization engines:
| Front door | Authorization engine |
|---|---|
storage.googleapis.com/<bucket>/<object> and /storage/v1/b/<bucket> | GCS IAM and per-object ACLs |
firebasestorage.googleapis.com/v0/b/<bucket>/o | Firebase Storage Security Rules |
A 403 from a GCS URL does not prove that Firebase Storage rules deny access. Always test both doors.
Auth
accounts.google.com or securetoken.google.com/<project>)<project> or <app-id>, identity in sub/uidExtract Project Config
From client bundle:
// apiKey, authDomain, projectId, appId, storageBucket, messagingSenderId
firebase.apps[0].options
Obtain Principals
Capture ID tokens for each.
Rules are not filters—a query must include constraints that make the rule true for all returned documents.
Common Gaps
allow read: if request.auth != null — any authenticated user reads all dataallow write: if request.auth != null — mass write accessisAdmin/role/tenantId fields)ownerId/orgId instead of resource.data.ownerId == request.auth.uidSecure Patterns
// Restrict write fields
request.resource.data.keys().hasOnly(['field1', 'field2', 'field3'])
// Enforce ownership
resource.data.ownerId == request.auth.uid &&
request.resource.data.ownerId == request.auth.uid
// Org membership check
exists(/databases/(default)/documents/orgs/$(org)/members/$(request.auth.uid))
Tests
where orgId == otherOrg; try queries without org filterownerId/orgId; attempt to flip privilege flagscollectionGroup queries that may bypass per-collection rulesstartAt/endAt/in/array-contains to probe rule edges and pagination cursorshttps://<project>.firebaseio.com/.json with and without authauth.uid and granular path checks.read/.write: true or auth != null at high-level nodesCommon Issues
/o?prefix= enumerates object keysFirebase Storage rules checks
Probe the rules door separately from GCS IAM and ACLs:
GET https://firebasestorage.googleapis.com/v0/b/<bucket>/o?prefix=<known-prefix>Write access is as important as read access and is routinely missed. Record status, response body, and object existence after each attempt; clean up only test objects that the test principal created.
Review rules source when present and flag:
allow read, write: if request.time < timestamp.date(...) — the common console test-mode time gate{allPaths=**} catch-allsrequest.auth != null as the sole authorization gaterequest.auth.token.roles.size() > 0 without role or tenant validationStorage rules use OR-across-matches semantics: a later permissive match can reopen a path that an earlier match denied. Review every matching path, not only the most specific-looking deny.
Bucket discovery
storageBucket from firebase.apps[0].options and NEXT_PUBLIC_FIREBASE_* values in JavaScript bundles and source.<project>.appspot.com and <project>.firebasestorage.app bucket conventions.ACL and IAM checks are separate
allUsers and allAuthenticatedUsers, including objects made public by Admin SDK makePublic() or writers using public: true. Per-object public ACLs persist after Firebase rules are tightened and can remain on older prefixes.allUsers and allAuthenticatedUsers.Tests
Content-Disposition: attachmentX-Content-Type-Options: nosniff; check for script executiononCall provides context.auth automatically; onRequest must verify ID tokens explicitly. Admin SDK bypasses rules—all ownership/tenant checks must be in code.
Common Gaps
uid/orgId from request body instead of context.authaud/iss verification when manually parsing tokensTests
Verification Requirements
Pitfalls
uid/account IDs from request body instead of context.auth.uidTests
aud/iss rejectionApp Check is not a substitute for authorization.
Bypasses
Tests
Apps often implement multi-tenant data models (orgs/<orgId>/...). Bind tenant from server context (membership doc or custom claim), not client payload.
Tests
firebase.json, .firebaserc, deployment scripts, CI configuration, and infrastructure code for storage.rules / firestore.rules declarations.firebase.json has no storage or firestore block, or the referenced rules file is absent from the tree, treat the live rules as unmanaged and force the live probe matrix. Absence of rules IaC is itself a finding; never conclude that there is nothing to review.auth != null, missing field validation)aud/iss) or trusting client uid/orgId