Skip to Main Content
Guides12 min readUpdated 24 March 2026

How to Architect Firebase Security Rules Using AI Prompt Architect

Firebase Security Rules are your last line of defence. If your rules are wrong, your entire database is exposed — regardless of how good your frontend validation is. This guide shows you how to use AI Prompt Architect to generate production-grade security rules that actually protect your data.

Why AI Gets Firebase Rules Wrong

When you ask an AI coding assistant to "write Firestore security rules", you typically get this:

// ❌ The AI default — dangerously permissive
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth != null;
    }
  }
}

This is catastrophically insecure. Any authenticated user can read and modify every document in your entire database — including other users' private data, admin configurations, and billing records.

Key insight: AI models default to permissive rules because they optimise for "it works" rather than "it's secure". A Master Prompt flips this default to "deny everything, then explicitly allow".

Step 1: Configure Your Security Model

In the AI Prompt Architect wizard, define your security architecture:

# Firebase Security Rules configuration
services:
  - Firestore (primary database)
  - Firebase Storage (user uploads)
  - Realtime Database (presence/typing indicators)

auth_model:
  provider: Firebase Authentication
  custom_claims:
    - role: ["user", "pro", "admin"]
    - orgId: string (multi-tenant)
  
security_principles:
  - Deny by default — every path must have explicit rules
  - Owner-only writes — users can only modify their own data
  - Role-based reads — admin can read all, users can read own
  - Validate all writes — check data types, sizes, required fields
  - Rate limiting — prevent abuse via resource rules

Step 2: Generate the Master Prompt

AI Prompt Architect generates a structured prompt that enforces your security model across all three Firebase services. Here's the Firestore rules it produces:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // ── Helper Functions ──────────────────────────────────
    function isAuthenticated() {
      return request.auth != null;
    }

    function isOwner(userId) {
      return isAuthenticated() && request.auth.uid == userId;
    }

    function hasRole(role) {
      return isAuthenticated() && request.auth.token.role == role;
    }

    function isAdmin() {
      return hasRole('admin');
    }

    function isValidString(field, minLen, maxLen) {
      return field is string
          && field.size() >= minLen
          && field.size() <= maxLen;
    }

    function isValidTimestamp(field) {
      return field is timestamp;
    }

    // ── User Profiles ─────────────────────────────────────
    match /users/{userId} {
      allow read: if isOwner(userId) || isAdmin();
      allow create: if isOwner(userId)
                    && isValidString(request.resource.data.displayName, 1, 100)
                    && request.resource.data.email == request.auth.token.email;
      allow update: if isOwner(userId)
                    && !request.resource.data.diff(resource.data)
                        .affectedKeys()
                        .hasAny(['role', 'createdAt', 'email']);
      allow delete: if false; // Soft delete only via Cloud Function
    }

    // ── Projects ──────────────────────────────────────────
    match /projects/{projectId} {
      allow read: if isAuthenticated()
                  && resource.data.ownerId == request.auth.uid;
      allow create: if isAuthenticated()
                    && request.resource.data.ownerId == request.auth.uid
                    && isValidString(request.resource.data.name, 1, 200);
      allow update: if isAuthenticated()
                    && resource.data.ownerId == request.auth.uid;
      allow delete: if isAuthenticated()
                    && resource.data.ownerId == request.auth.uid;
    }

    // ── Admin-Only Collections ────────────────────────────
    match /system_config/{docId} {
      allow read: if isAdmin();
      allow write: if false; // Cloud Functions only
    }

    // ── Catch-All: Deny Everything Else ───────────────────
    match /{document=**} {
      allow read, write: if false;
    }
  }
}

Step 3: Storage Rules

The Master Prompt also generates matching Firebase Storage rules with file type and size validation:

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {

    function isAuthenticated() {
      return request.auth != null;
    }

    function isOwner(userId) {
      return request.auth.uid == userId;
    }

    function isImageType() {
      return request.resource.contentType.matches('image/(png|jpeg|webp|gif)');
    }

    function isUnderSizeLimit(maxMB) {
      return request.resource.size < maxMB * 1024 * 1024;
    }

    // User avatars — owner only, images only, max 5MB
    match /avatars/{userId}/{fileName} {
      allow read: if isAuthenticated();
      allow write: if isOwner(userId)
                   && isImageType()
                   && isUnderSizeLimit(5);
    }

    // Project assets — owner only, max 25MB
    match /projects/{userId}/{projectId}/{fileName} {
      allow read: if isAuthenticated();
      allow write: if isOwner(userId)
                   && isUnderSizeLimit(25);
    }

    // Deny everything else
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

Common Anti-Patterns the Master Prompt Prevents

Anti-PatternRiskMaster Prompt Fix
allow read, write: if trueFull public accessDeny-by-default catch-all rule
if request.auth != null on all pathsAny user reads any dataOwner checks + role-based access
No field validation on writesMalicious data injectionType, size, and required field checks
No file type checks in StorageExecutable upload attackscontentType.matches() validation
Wildcard {document=**} allowsNew collections auto-exposedExplicit per-collection rules only
Client-side role checks onlyTrivially bypassableCustom claims verified in rules

Step 4: Test with the Firebase Emulator

The Master Prompt includes testing instructions. Use the Firebase Emulator Suite to validate your rules before deploying:

# Start the emulator
firebase emulators:start --only firestore,storage

# Run security rules tests
firebase emulators:exec "npm test -- --testPathPattern=rules"

Key Takeaways

  1. Deny by default — the Master Prompt ensures every path starts locked down
  2. Validate everything — data types, string lengths, file sizes, and content types are all checked in rules
  3. Custom claims over client data — roles are verified from the auth token, not from user-submitted fields
  4. Test before deploy — the Firebase Emulator catches rule errors before they hit production
  5. Separate concerns — admin operations go through Cloud Functions, not direct client writes
Secure your app now: Create a free account and generate battle-tested Firebase Security Rules in under 5 minutes.

Ready to build better prompts?

Start using AI Prompt Architect for free today.

Get Started Free

We value your privacy

We use cookies and similar technologies to ensure our website works properly, analyze traffic, and personalize your experience. Under the GDPR, CCPA, and CPRA, you have the right to choose which categories, apart from necessary cookies, you allow.