dreamlabs.pro/services/firestore-security-rules-checklist · Updated Oct 7, 2026

[Free checklist]

Firestore and Cloud Storage Security Rules Checklist

Firebase lets a small team ship a real app without running a server, and Security Rules are what make that safe. Firebase's own docs say your API key only identifies your project; IAM, Security Rules and App Check decide who gets in. Get the rules right and the config in your app is harmless by design, a customer's security questionnaire becomes a short reply, and every new feature ships with a rule and a test instead of a question mark. This checklist covers Firestore and Cloud Storage in 24 checks. Each one says what to look for, why it matters, how to test it in the console, the emulator or a terminal, and which Firebase documentation backs it. Run the tests only against projects you own, ideally a staging copy.

Updated · 24 checks · 7 sections

[01]

Start here: what can a stranger reach?

Firebase is clear that your web API key and project ID are public by design: they identify your project, and Security Rules decide who gets in. These checks show what anyone holding your app's config can do today.

  • Why it matters and how to test it

    Why it matters

    Firebase's own warning about open rules is that anyone who guesses your project ID can steal, modify or delete the data. A condition that only checks the date is the same open door until that date passes. Projects created in test mode start with rules that let anyone read and overwrite your data, so this is the first thing to look for.

    How to test

    Open Firestore > Rules in the Firebase console (or the rules file named in firebase.json) and search for if true and request.time. Then open Rules playground, pick a read on a private path such as /users/some-id, set Authentication to unauthenticated, and click Run. Finally, ask the REST API for a collection with no token at all: Firestore evaluates unauthenticated REST requests against your rules, so a private collection should answer with a 403.

    # Replace PROJECT_ID and the collection name. Expect 403 PERMISSION_DENIED.
    curl -s "https://firestore.googleapis.com/v1/projects/PROJECT_ID/databases/(default)/documents/users?pageSize=5"

    Source: Firebase docs: Fix insecure rules (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    When more than one match statement applies to a document, Firestore allows the request if any of them allows it. One permissive catch-all, often left over from early development, cancels every careful rule written after it.

    How to test

    List every match block that contains =**. For each one, ask whether everything it grants is acceptable for every path it covers. In Rules playground, try a sensitive path that a specific rule should deny; if it comes back allowed, an overlapping match is winning.

    Source: Firebase docs: Structuring Cloud Firestore Security Rules

  • Why it matters and how to test it

    Why it matters

    A CLI deploy overwrites rules edited in the console, and console edits never make it back to your repo, so the two drift apart. A project can also hold several Firestore databases: each named database gets its own rules, deployed through the Firebase CLI, and the console and Admin SDK only deploy rules to the default database.

    How to test

    Compare the Rules tab in the console with the rules file in your repo. List the project's databases and confirm each one is mapped to a rules file in firebase.json. From then on, deploy rules only from the repo.

    firebase firestore:databases:list
    firebase deploy --only firestore:rules

    Source: Firebase docs: Manage and deploy Firebase Security Rules

[02]

Signed in is not the same as allowed

Most real-world rule problems aren't open databases. They're rules that let any signed-in user do what only one user should.

  • Why it matters and how to test it

    Why it matters

    Firebase lists 'any logged-in user has read and write access' among its insecure patterns. Unless you've turned off sign-up, anyone can create an account in your project using the public API key, so 'signed in' often just means 'registered'.

    How to test

    Search your rules for auth != null and review every match where it's the only condition. Then prove it from outside: create a throwaway account with the Auth REST API and the API key from your app's config, and repeat the earlier request as that user. Do this against a staging project, or delete the test user afterwards.

    # 1. Create a test user (email/password sign-in must be enabled)
    curl -s 'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=API_KEY' \
      -H 'Content-Type: application/json' \
      --data-binary '{"email":"[email protected]","password":"CHOOSE_A_PASSWORD","returnSecureToken":true}'
    
    # 2. Copy idToken from the response and read another user's data as this user
    curl -s -H "Authorization: Bearer ID_TOKEN" \
      "https://firestore.googleapis.com/v1/projects/PROJECT_ID/databases/(default)/documents/users?pageSize=5"

    Source: Firebase docs: Fix insecure rules (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    Firebase's security checklist puts it plainly: anyone could create an anonymous account in your project, and anonymous auth is not a replacement for user sign-in. Anonymous users pass request.auth != null like everyone else.

    How to test

    Check Authentication > Sign-in method for Anonymous. If it's enabled, protected reads and writes should also require request.auth.token.firebase.sign_in_provider != 'anonymous' or request.auth.token.email_verified == true. In Rules playground, rerun a protected request as an authenticated anonymous user and confirm it's denied. From outside, the same signUp endpoint returns an anonymous token when the provider is on.

    # Returns an anonymous idToken if Anonymous sign-in is enabled
    curl -s 'https://identitytoolkit.googleapis.com/v1/accounts:signUp?key=API_KEY' \
      -H 'Content-Type: application/json' --data-binary '{"returnSecureToken":true}'

    Source: Firebase docs: Security checklist

  • Why it matters and how to test it

    Why it matters

    Emails aren't always verified at sign-in. A rule meaning 'anyone with an @yourcompany.com address' can be satisfied by someone who typed that address without owning it.

    How to test

    Search your rules for email. Every condition on an address or domain should sit next to an email_verified == true check. Cover it with an emulator test that signs in with a matching but unverified email and expects a denial.

    // Emulator test (see the unit-test item for setup)
    const unverified = testEnv.authenticatedContext('u1', {
      email: '[email protected]',
      email_verified: false,
    }).firestore();
    await assertFails(getDoc(doc(unverified, 'internal/roadmap')));

    Source: Firebase docs: Fix insecure rules (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    Firebase says custom claims should only be set from a privileged server environment with the Admin SDK, and the ID token delivers them in a form users can't tamper with. A role stored on a user's own profile document, which that user is allowed to update, is a role they can give themselves.

    How to test

    Find every rule that checks a role (token.admin, .data.role, isAdmin). For claims, confirm that only server code calls setCustomUserClaims. For role documents, confirm their owners can't change the role field (see the field allowlist check). Emulator test: as a normal user, update your own document with role: 'admin' and assert it fails.

    Source: Firebase docs: Control access with custom claims and security rules

[03]

Writes that keep your data honest

  • Why it matters and how to test it

    Why it matters

    Checking ownership of the existing document isn't enough. Firebase's content-owner pattern checks request.resource.data on create, and both the stored and the incoming document on update, so nobody can create records in someone else's name or hand a record to another account.

    How to test

    For each owned collection, look for allow create: if request.auth.uid == request.resource.data.ownerId and an update rule that checks the owner on both resource.data and request.resource.data. Emulator test: as Bob, create a document with ownerId: 'alice', then try to update one of Alice's documents. Both should fail.

    Source: Firebase docs: Fix insecure rules (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    Rules are schemaless. Without a field allowlist, a user who may edit their profile may also edit role, plan, credits or verified on it. Firebase calls the hasOnly() approach generally more secure, because a field you add later stays locked until you allow it.

    How to test

    Every allow update should carry an affectedKeys().hasOnly() list or an equivalent check. Emulator test: as the document owner, update a protected field and assert it fails, then update an allowed field and assert it succeeds.

    // firestore.rules
    allow update: if request.auth.uid == resource.data.ownerId
      && request.resource.data.diff(resource.data).affectedKeys()
           .hasOnly(['displayName', 'photoURL', 'bio']);

    Source: Firebase docs: Control access to specific fields (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    Nothing at the database level stops a client writing a string where you expect a number, or an extra field you never designed for. In an app with no server of its own, rules are the only server-side validation there is.

    How to test

    Review each allow create for key and type checks. Emulator test: create a document with an extra field, one with a missing required field and one with a wrong type. Each should fail.

    Source: Firebase docs: Control access to specific fields (Cloud Firestore)

[04]

Reads that show only what they should

  • Why it matters and how to test it

    Why it matters

    Being able to open one document by ID is very different from being able to download a whole collection. Rules are not filters: a query only succeeds if every document it could return is allowed. That means you can require queries to filter on the caller's ID, and cap their size with request.query.limit.

    How to test

    Look for plain allow read on sensitive collections and consider splitting it into get and list. Emulator test: run an unfiltered query as a normal user and assert it fails, then run the same query filtered to the user's own documents and assert it succeeds.

    const bob = testEnv.authenticatedContext('bob').firestore();
    await assertFails(getDocs(collection(bob, 'orders')));
    await assertSucceeds(getDocs(query(collection(bob, 'orders'), where('ownerId', '==', 'bob'))));

    Source: Firebase docs: Securely query data (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    Reads are all or nothing per document. Firebase says outright that security rules alone can't stop users reading specific fields within a document, so a public profile that also stores a phone number publishes the phone number.

    How to test

    For every collection other users can read, list its fields and mark anything private. Move those fields to a subcollection such as /users/{uid}/private/{doc} with owner-only rules, and add an emulator test proving a second user can read the public document but not the private one.

    Source: Firebase docs: Control access to specific fields (Cloud Firestore)

  • Why it matters and how to test it

    Why it matters

    Rules apply only at the path they match: access granted on cities doesn't extend to cities/{id}/landmarks. Collection group queries need rules_version = '2' and a {path=**} match, which is easy to write more broadly than you meant.

    How to test

    Map every path your app reads or writes, subcollections included, against your match blocks. Unmatched paths are denied, which is safe. Any {path=**} match deserves a test proving one user can't query another user's documents across the group.

    Source: Firebase docs: Structuring Cloud Firestore Security Rules

[05]

Cloud Storage: files get the same care as data

  • Why it matters and how to test it

    Why it matters

    Firebase recommends initializing Storage rules to deny all access and adding rules as you build. Its user-private pattern, match /users/{userId}/{fileName} with request.auth.uid == userId, keeps one user's uploads away from everyone else.

    How to test

    Open Storage > Rules. Flag if request.auth != null on broad paths and if true anywhere outside a deliberately public folder. Emulator test: seed a file under users/alice/ with withSecurityRulesDisabled, then as Bob try to read and overwrite it. Both should fail.

    import { ref, getBytes, uploadBytes } from 'firebase/storage';
    const bob = testEnv.authenticatedContext('bob').storage();
    await assertFails(getBytes(ref(bob, 'users/alice/id-card.jpg')));
    await assertFails(uploadBytes(ref(bob, 'users/alice/avatar.png'), new Uint8Array([1])));

    Source: Firebase docs: Use conditions in Firebase Security Rules for Cloud Storage

  • Why it matters and how to test it

    Why it matters

    Without limits, anyone allowed to upload can store files of any size or type in your bucket, on your bill. Storage rules can check request.resource.size and request.resource.contentType before the upload is accepted.

    How to test

    Each upload rule should include something like request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'). Emulator test: upload an oversized file and a non-image to an image path. Both should fail.

    Source: Firebase docs: Understand Firebase Security Rules for Cloud Storage

  • Why it matters and how to test it

    Why it matters

    allow read covers both, so anyone who may open a file under a path may also enumerate every file name under it. Storage rules let you split read into get and list (listing requires rules version 2).

    How to test

    Search Storage rules for allow read on folders holding user files and consider allow get instead. Emulator test: call listAll() on a user folder as a signed-out client and assert it fails.

    import { ref, listAll } from 'firebase/storage';
    const anon = testEnv.unauthenticatedContext().storage();
    await assertFails(listAll(ref(anon, 'users/alice')));

    Source: Firebase docs: Learn the core syntax of the Firebase Security Rules for Cloud Storage language

  • Why it matters and how to test it

    Why it matters

    A download URL is built for sharing; Firebase describes it as the option for when you 'just want a URL to share'. By contrast, the SDK's direct-download functions (getBlob(), getBytes()) 'allow for finer-grained access control via Firebase Security Rules'.

    How to test

    Search your Firestore data and code for stored firebasestorage.googleapis.com URLs and check who can read the documents that hold them. Open one in a private browser window with no sign-in. If the file loads, the URL itself is the access control, so treat it like a password.

    Source: Firebase docs: Download files with Cloud Storage on Web

  • Why it matters and how to test it

    Why it matters

    Requests made through the Google Cloud Storage APIs use Cloud Storage access control, not Firebase Authentication and Storage Security Rules. An IAM grant to allUsers makes objects readable by anyone on the internet, whatever your rules say.

    How to test

    Print the bucket's IAM policy and look for allUsers or allAuthenticatedUsers in any binding. Your bucket name is the storageBucket value in your app's Firebase config.

    gcloud storage buckets get-iam-policy gs://BUCKET_NAME

    Source: Firebase docs: Integrate with Google Cloud (Cloud Storage)

[06]

Around the rules: keys, servers and abuse

  • Why it matters and how to test it

    Why it matters

    Server client libraries bypass all Firestore Security Rules and authorize through IAM instead. A service account key in a web bundle or mobile app is full database access for whoever extracts it. A Cloud Function that acts with Admin rights for an unverified caller is the same gap with more steps.

    How to test

    Search your built web bundle and app source for private key material (command below). In every callable function, confirm the handler rejects calls without request.auth and acts on request.auth.uid, never on a user ID sent in the request body.

    grep -rnE "BEGIN PRIVATE KEY|private_key|client_email" dist/ build/ src/ 2>/dev/null

    Source: Firebase docs: Get started with Cloud Firestore Security Rules

  • Why it matters and how to test it

    Why it matters

    Firebase API keys are public by design because authorization comes from IAM, Security Rules and App Check. That only holds while the key is limited to Firebase APIs. Firebase says never to include the Gemini Developer API in the allowlist of a publicly accessible key, and a Gemini API key should never be in your code or config at all.

    How to test

    In Google Cloud console > APIs & Services > Credentials, open the key from your app's config and read its API restrictions. It should list only Firebase-related APIs, and not Generative Language API.

    Source: Firebase docs: Learn about using and managing API keys for Firebase

  • Why it matters and how to test it

    Why it matters

    Once enforcement is on for a product, Firebase rejects every unverified request to it, so scripts and forged clients built from your public config get turned away. App Check complements Authentication and rules; it doesn't decide which user may see which document.

    How to test

    In the Firebase console, open Security > App Check > APIs and read the request metrics for Firestore and Storage. 'Unknown origin' requests are traffic that doesn't look like your app. When you're confident enforcing won't lock out legitimate users (older app versions show up as 'Outdated client'), click Enforce; it can take up to 15 minutes to apply. Afterwards, the unauthenticated REST request from the first check should be rejected.

    Source: Firebase docs: Enable App Check enforcement

  • Why it matters and how to test it

    Why it matters

    Enumeration protection stops people using your auth endpoints to discover which email addresses have accounts; it's on by default for projects created on or after September 15, 2023. If users should never register themselves, disabling user actions makes Firebase refuse client sign-ups with auth/admin-restricted-operation, which also closes the 'anyone can sign up' door from the second section.

    How to test

    In the Firebase console, go to Security > Authentication > Settings and open User actions. Check email enumeration protection, and whether account creation by end users should be allowed at all. If you use email and password sign-in, Firebase also recommends tightening the Identity Toolkit API quota in Google Cloud console.

    Source: Firebase docs: Authenticate with Firebase using password-based accounts (Web)

  • Why it matters and how to test it

    Why it matters

    Firebase's checklist recommends separate projects so test data, test accounts and loosened test rules never touch production, and budget alerts so unusual traffic shows up before the invoice does.

    How to test

    Confirm the config in your production build points at the production project, and that no development config ships with it. In Google Cloud Billing, confirm a budget with alert thresholds covers the production project.

    Source: Firebase docs: Security checklist

[07]

Keep it closed

  • Why it matters and how to test it

    Why it matters

    A rule that passes review today can break quietly with the next feature. Firebase recommends unit-testing rules with the emulator and adding the tests to CI, and treating rules like a schema: write the rule when you add the document type, not as a pre-launch chore.

    How to test

    Install @firebase/rules-unit-testing. For each collection, write allow and deny cases for the owner, another user and a signed-out visitor. Run them with firebase emulators:exec locally and in CI, so a deny test that starts passing fails the build.

    // rules.test.js (run: firebase emulators:exec --only firestore "npm test")
    import fs from 'node:fs';
    import { initializeTestEnvironment, assertFails, assertSucceeds } from '@firebase/rules-unit-testing';
    import { doc, getDoc, setDoc } from 'firebase/firestore';
    
    const testEnv = await initializeTestEnvironment({
      projectId: 'demo-rules-audit',
      firestore: { rules: fs.readFileSync('firestore.rules', 'utf8') },
    });
    
    const alice = testEnv.authenticatedContext('alice').firestore();
    const bob = testEnv.authenticatedContext('bob').firestore();
    const visitor = testEnv.unauthenticatedContext().firestore();
    
    await assertSucceeds(setDoc(doc(alice, 'users/alice'), { ownerId: 'alice', displayName: 'A' }));
    await assertFails(getDoc(doc(bob, 'users/alice')));
    await assertFails(getDoc(doc(visitor, 'users/alice')));
    await assertFails(setDoc(doc(bob, 'users/alice'), { ownerId: 'bob' }));
    
    await testEnv.cleanup();

    Source: Firebase docs: Build unit tests (Security Rules)

[FAQs]

Frequently asked questions

Is it safe that my Firebase config and API key are visible in my app?

Yes, as long as two things hold. Firebase says API keys for Firebase services only identify your project; authorization comes from IAM, Security Rules and App Check. So the key needs to be restricted to Firebase APIs (and kept off the Gemini Developer API), and your rules need to pass this checklist. Service account keys and Gemini API keys are different: those must stay secret.

Firebase emailed me that my Firestore database has insecure rules. Where do I start?

With the first section. Open the Rules tab, look for if true, date-only conditions and request.auth != null used alone, and check broad {document=**} matches. Firebase's guidance for that alert is to change your rules and test them, with Rules playground for quick checks and the emulator for anything you want to keep.

Do Cloud Functions and the Admin SDK follow my rules?

No. Server client libraries bypass Firestore Security Rules and authorize through IAM, which is why server code has to check the caller itself. Rules protect what clients can do directly; your functions are responsible for everything they do on a user's behalf.

Does App Check replace security rules?

No. Firebase describes App Check and Authentication as complementary: App Check is about whether a request comes from your genuine app, while Authentication and rules decide what a given user may read and write. You want both.

Can an AI coding agent write my rules?

It can give you a good first draft, and Firebase's own docs now include prompts for coding agents. The catch is that an agent is usually optimizing for the feature working, and a rule that blocks a feature looks exactly like a bug. Keep the emulator tests from the last section in CI, so a loosened rule fails the build instead of shipping.

I only have an hour. What should I do first?

Run the outside-in tests from the first two sections: an unauthenticated REST read, then the same read as a freshly created test account. Then check Storage rules and the bucket's IAM policy. If those come back clean, you've covered the exposures that need no skill to find.

[Sources]

Sources

Every check links to the documentation behind it. All 29 sources below were opened on Oct 7, 2026.

  1. Firebase: Fix insecure rules (Cloud Firestore) Google (Firebase docs) · Last updated 2026-10-06 UTC
  2. Firebase: Get started with Cloud Firestore (quickstart) Google (Firebase docs) · Last updated 2026-10-06 UTC
  3. Firebase: Use the Cloud Firestore REST API Google (Firebase docs) · Last updated 2026-10-06 UTC
  4. Firebase: Firebase Auth REST API reference Google (Firebase docs) · Last updated 2026-10-06 UTC
  5. Firebase: Structuring Cloud Firestore Security Rules Google (Firebase docs) · Last updated 2026-10-06 UTC
  6. Firebase: Manage and deploy Firebase Security Rules Google (Firebase docs) · Last updated 2026-10-06 UTC
  7. Firebase: Create and manage Cloud Firestore databases Google (Firebase docs) · Last updated 2026-10-06 UTC
  8. Firebase: Security checklist Google (Firebase docs) · Last updated 2026-10-06 UTC
  9. Firebase: Control access with custom claims and security rules Google (Firebase docs) · Last updated 2026-10-06 UTC
  10. Firebase: Control access to specific fields (Cloud Firestore) Google (Firebase docs) · Last updated 2026-10-06 UTC
  11. Firebase: Securely query data (Cloud Firestore) Google (Firebase docs) · Last updated 2026-10-06 UTC
  12. Firebase: Use conditions in Firebase Security Rules for Cloud Storage Google (Firebase docs) · Last updated 2026-10-06 UTC
  13. Firebase: Understand Firebase Security Rules for Cloud Storage Google (Firebase docs) · Last updated 2026-10-06 UTC
  14. Firebase: Learn the core syntax of the Firebase Security Rules for Cloud Storage language Google (Firebase docs) · Last updated 2026-10-06 UTC
  15. Firebase: Download files with Cloud Storage on Web Google (Firebase docs) · Last updated 2026-10-06 UTC
  16. Firebase: Download files with Cloud Storage on Android Google (Firebase docs) · Last updated 2026-10-06 UTC
  17. Firebase: Integrate with Google Cloud (Cloud Storage) Google (Firebase docs) · Last updated 2026-10-06 UTC
  18. Google Cloud: Make data public (Cloud Storage) Google Cloud docs · Last updated 2026-10-07 UTC
  19. Google Cloud: Use IAM permissions (Cloud Storage) Google Cloud docs · Last updated 2026-10-07 UTC
  20. Firebase: Get started with Cloud Firestore Security Rules Google (Firebase docs) · Last updated 2026-10-06 UTC
  21. Firebase: Call functions from your app (callable functions) Google (Firebase docs) · Last updated 2026-10-06 UTC
  22. Firebase: Learn about using and managing API keys for Firebase Google (Firebase docs) · Last updated 2026-10-06 UTC
  23. Firebase: App Check Google (Firebase docs) · Last updated 2026-10-06 UTC
  24. Firebase: Enable App Check enforcement Google (Firebase docs) · Last updated 2026-10-06 UTC
  25. Firebase: Monitor App Check request metrics Google (Firebase docs) · Last updated 2026-10-06 UTC
  26. Firebase: Authenticate with Firebase using password-based accounts (Web) Google (Firebase docs) · Last updated 2026-10-06 UTC
  27. Firebase: Users in Firebase projects Google (Firebase docs) · Last updated 2026-10-06 UTC
  28. Firebase: Build unit tests (Security Rules) Google (Firebase docs) · Last updated 2026-10-06 UTC
  29. Firebase: Test your Cloud Firestore Security Rules (emulator) Google (Firebase docs) · Last updated 2026-10-06 UTC