if true in production
Usually the aftermath of an expired test mode. It reads like a placeholder and behaves like a public database.
Guides / Firebase security
Plenty of AI-built apps, including many built by South African founders, run on Firebase. The pattern of failure is the same as everywhere else: the demo works, the database is open, and nobody notices until someone hostile does. This guide shows you how to check your project and write rules that hold.
The Firebase config block in your frontend, apiKey included, identifies
your project. It does not authorise anything. Like Supabase's anon key (now the
publishable key), it is designed to ship in client code, and anyone can read it there. What decides whether a stranger
can read your data is Firebase Security Rules: the per-request conditions attached to
Cloud Firestore, the Realtime Database, and Cloud Storage.
When the rules are open, the public config is full access to your database. No exploit, no skill, just a URL. And AI coding tools set projects up fast, wire the happy path, and rarely circle back to the rules.
When you create a Firestore or Realtime Database in test mode, Firebase writes rules that allow anyone to read and write until an expiry date about 30 days out:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.time < timestamp.date(2026, 8, 3);
}
}
}
Ending one: the date passes, every request in your app starts failing with
permission-denied, and a rushed founder "fixes" it by changing the condition to
if true. The app works again, permanently open. Ending two: you are still
inside the window right now, which means your database is open right now. Either way,
the fix is the same: real rules.
curl "https://YOUR-PROJECT-default-rtdb.firebaseio.com/.json"Data back means the whole tree is public. A permission-denied error is what you want to see.
curl "https://firestore.googleapis.com/v1/projects/YOUR-PROJECT/databases/(default)/documents/users"Documents in the response mean that collection is readable by anyone.
if true and for expired test-mode timestamps.
If a probe returned personal information, treat it as a potential incident. Under POPIA, publicly reachable personal data can carry notification obligations; our POPIA guide for app founders covers what that means in practice.
Rules are conditions evaluated by Firebase on every request. The two building blocks
are request.auth, who is asking, and request.resource, what
they are trying to write. A sane baseline for user-owned data:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read, update, delete: if request.auth != null
&& request.auth.uid == userId;
allow create: if request.auth != null
&& request.auth.uid == userId;
}
match /{document=**} {
allow read, write: if false;
}
}
}
The final block is the important habit: default deny. Anything you did not explicitly allow is refused, so a collection added by your AI tool next week ships closed instead of open.
Two distinctions that catch vibe-coded apps: first,
request.auth != null means "any signed-in person", not "the right
person". Any stranger can create an account, so authentication alone is not
authorisation; compare the UID or a role. Second, the Admin SDK bypasses rules
entirely. That is correct for trusted server code, and catastrophic if your service
account JSON ever reaches a browser or a public repo.
Validate writes too. Rules can enforce shape and bounds, for example
request.resource.data.price is number && request.resource.data.price >= 0,
which blocks a whole class of tampered-client tricks.
Where it goes wrong
Usually the aftermath of an expired test mode. It reads like a placeholder and behaves like a public database.
Rules that only check request.auth != null let any stranger with a free account read every user's data.
Without a closing match-all deny, every collection your AI tool adds next sprint starts life exposed.
Firestore locked, Storage forgotten. Uploaded IDs, invoices, and photos leak just as badly as database rows.
The Admin SDK JSON bypasses all rules. In a public repo or client bundle it is game over; rotate it immediately.
Hiding the admin screen does not protect the collection behind it. If the rule is not enforced by Firebase, it is not enforced.
Questions
Yes. The apiKey in your Firebase config identifies your project; it does not grant access on its own. Access is decided by Security Rules, plus App Check if you enable it. The key only looks like a secret. The rules are the real control, which is why an open ruleset is so dangerous.
Requests from your app start failing with permission-denied errors, usually about 30 days after the database was created. The correct response is to write real rules for the collections your app uses. The common wrong response is changing the rule to allow read, write: if true, which silently turns your database public.
No. The Admin SDK and service accounts bypass Security Rules entirely, which is intended: trusted server code needs full access. It also means your service account JSON is a master key. Keep it in server-side secret storage only, and rotate it immediately if it has ever been committed to a repo.
Three layers: the Rules Playground in the console for quick simulations, the Firebase emulator suite with unit tests for regressions, and signed-out curl probes against your live project for ground truth. If you only do one, do the curl probes; they test what an attacker actually sees.
Lock the rules first, then assess. Work out which collections were reachable and whether they held personal information. If they did, treat it as a potential incident under POPIA, including possible notification duties, and consider a broader review, because an open database is rarely the only gap in an AI-built app.
Beyond the rules
Secrets, sign-in, data integrity, reliability, and hosting you own: our senior engineers review the app you built with AI and give you a ranked list of what must be fixed before real users, what can wait, and what is already fine.