How I Would Fix database rules leaking customer data in a React Native and Expo automation-heavy service business Using Launch Ready.
The symptom is usually blunt: one user opens the app and sees another customer's records, automation logs, invoices, bookings, or internal notes. In a...
How I Would Fix database rules leaking customer data in a React Native and Expo automation-heavy service business Using Launch Ready
The symptom is usually blunt: one user opens the app and sees another customer's records, automation logs, invoices, bookings, or internal notes. In a React Native and Expo service business, that is not just a bug, it is a trust failure that can trigger support load, refunds, compliance risk, and account churn.
The most likely root cause is weak database authorization rules or client-side queries that are too broad. The first thing I would inspect is the exact read path from the Expo app to the backend: which collection or table is queried, what auth token is attached, and whether row-level access is enforced on the server or only assumed in the UI.
Triage in the First Hour
1. Check whether the leak is reproducible with two test accounts.
- Create User A and User B.
- Log in as each one on separate devices or simulators.
- Confirm whether User A can see User B's data through normal screens.
2. Inspect recent logs for auth and data access patterns.
- Look at API gateway logs, backend logs, and database audit logs.
- Search for requests with missing user IDs, empty auth claims, or unusually wide queries.
3. Review the last deployment.
- Identify whether the issue started after a schema change, rule change, SDK upgrade, or Expo release.
- Check if there was a rushed hotfix that relaxed permissions.
4. Audit database rules or security policies first.
- Firestore rules, Supabase RLS policies, Firebase Storage rules, Postgres grants, or custom API authorization.
- Confirm whether reads are scoped by authenticated user identity.
5. Inspect the client queries in the Expo app.
- Find any query that fetches all records and filters locally on the device.
- Check for hard-coded admin paths used in production builds.
6. Review secrets and environment variables.
- Make sure prod keys are not mixed with staging keys.
- Confirm that service-role keys are never bundled into the mobile app.
7. Check monitoring and alerting.
- Look for spikes in 403s, 401s, unusual read volume, or support tickets mentioning "wrong account".
8. Freeze risky changes until containment is clear.
- Pause new releases.
- Disable any exposed admin endpoints if they are not needed immediately.
## Quick sanity check for broad access patterns grep -R "select.*\*" . grep -R "getAll\|fetchAll\|listAll" . grep -R "serviceRole\|adminKey\|masterKey" .
Root Causes
1. Missing row-level security or equivalent policy enforcement
- How to confirm: inspect database policies directly and test with two non-admin users.
- If a user can read rows without an ownership filter on the server side, this is the root issue.
2. Client-side filtering instead of server-side authorization
- How to confirm: find queries that return all rows and then filter by `userId` in JavaScript.
- This fails as soon as someone bypasses the UI or calls the endpoint directly.
3. Service role key exposed in the mobile app or shared config
- How to confirm: search Expo env files, build configs, and bundled JS for privileged keys.
- If a secret can be extracted from the app bundle, assume it is compromised.
4. Broken auth claim mapping
- How to confirm: compare `auth.uid`, session subject claims, and database ownership fields.
- If records are tied to email while auth uses an immutable user ID, mismatches can leak data across accounts.
5. Over-permissive storage rules or signed URL logic
- How to confirm: test file downloads for customer uploads, PDFs, images, exports, and receipts.
- If storage objects are public by default or signed URLs last too long, data exposure continues even after login fixes.
6. Admin automation endpoints reusing production credentials
- How to confirm: inspect background jobs, webhooks, Zapier-style automations, and internal scripts for shared credentials.
- Automation-heavy businesses often over-grant access so workflows keep working under deadline pressure.
The Fix Plan
I would fix this in layers so we stop the leak first and then clean up the architecture without breaking production again.
1. Contain access immediately
- Disable any public endpoint that returns customer records without auth checks.
- Rotate any suspect API keys or service credentials if they may have been exposed.
- If necessary, temporarily restrict reads to authenticated users only while I verify policies.
2. Move authorization to the server
- Enforce ownership checks in database rules or RLS policies.
- Do not rely on React Native screens to hide data after it has already been returned.
3. Scope every query by tenant or owner
- Every read should include `user_id`, `account_id`, or `tenant_id` at the data layer.
- For multi-step automations, I would verify each job uses the correct tenant context before reading or writing records.
4. Separate public app credentials from privileged backend secrets
- Expo should only contain public configuration values that are safe to ship.
- Any admin access must live behind a backend function or server route with strict auth checks.
5. Lock down storage access
- Make customer files private by default.
- Generate short-lived signed URLs only after checking ownership on the server.
6. Add safe fallback behavior
- If auth fails or policy evaluation fails, return no data rather than partial data from another customer.
- This avoids accidental cross-account leakage during edge cases like token refresh failures.
7. Patch deployment hygiene
- Verify staging and production environments use separate databases and separate secrets.
- Confirm Cloudflare caching does not cache personalized JSON responses across users.
8. Ship with observability turned on
- Log denied reads without storing sensitive payloads.
Track which policy blocked which request so future issues are diagnosable without exposing customer content.
Here is how I would think about it:
My preference is always server-enforced authorization first. It is slower than patching UI filters only once you count real-world damage from exposed customer data.
Regression Tests Before Redeploy
I would not redeploy until these checks pass:
1. Cross-account read test
- User A cannot read User B's records through app screens or direct API calls.
- Acceptance criteria: 0 cross-tenant reads across 20 repeated attempts.
2. Anonymous access test
- Unauthenticated requests must fail closed on protected endpoints.
- Acceptance criteria: 401 or 403 returned consistently with no data payload.
3. Privileged secret test
- Verify no admin key exists in Expo bundle output or mobile config files.
- Acceptance criteria: no service-role credentials present in shipped artifacts.
4. Storage access test
- Customer uploads cannot be fetched by guessing URLs unless explicitly authorized.
- Acceptance criteria: private assets require valid ownership plus short-lived access tokens.
5. Automation workflow test
- Run background jobs against two different accounts and confirm each job stays within its own tenant scope.
Acceptance criteria: 100 percent of sample jobs use correct account context.
6. Cache isolation test Verify Cloudflare and any CDN layer do not cache personalized responses globally. Acceptance criteria: cache headers prevent cross-user response reuse for private endpoints.
7. Device matrix smoke test Test iOS simulator plus one physical Android device using fresh installs and expired sessions. Acceptance criteria: login refresh works without exposing stale account data.
8. Audit log review Confirm denied access attempts are logged safely without leaking payloads into logs or error trackers, Acceptance criteria: logs contain request metadata only.
For a release like this I would target at least 95 percent coverage on authorization-related tests around critical paths before shipping again. For an automation-heavy service product with customer records at stake, that is cheap compared with one leaked invoice thread turning into days of support cleanup.
Prevention
I would put guardrails around this so it does not come back six weeks later when someone ships a quick feature under pressure.
- Security review on every data-access change
Any PR touching queries, policies, or storage rules gets manual review before merge, with one question repeated every time: "Can this request read someone else's data?"
- Least privilege everywhere
Use separate roles for app users, admins, and background jobs, and keep production secrets out of mobile clients entirely,
- Monitoring for abnormal reads
Set alerts for spikes in list queries, mass exports, or repeated forbidden requests from one account,
- Error handling that fails closed
If auth context is missing, return nothing rather than guessing,
- UX guardrails for sensitive actions
Show clear account context, especially where operators manage multiple clients from one dashboard,
- Performance discipline on private data endpoints
Add indexes on ownership columns, keep p95 reads under 200 ms, and avoid expensive scans that tempt developers to remove filters later,
- Dependency hygiene
Review Expo SDK updates, auth libraries, and backend packages for breaking security behavior before upgrading production,
- Red team mindset for AI-assisted automations
If prompts can trigger tools, test prompt injection, data exfiltration attempts, and unsafe tool chaining before launch,
When to Use Launch Ready
Launch Ready fits when you need this fixed fast without turning it into a month-long rebuild. I handle domain setup, email deliverability, Cloudflare, SSL, deployment, secrets, monitoring, and handover so your app can go back online safely instead of limping along with hidden risk.
This sprint makes sense if you already have:
- A working React Native and Expo codebase
- Access to your hosting,
database, Cloudflare, and domain registrar accounts
- A list of current environments:
dev, staging, prod
What I need from you before starting:
- Admin access to hosting and database tooling
- The current repo plus build instructions
- A short description of what leaked:
customer profiles, bookings, invoices, files, or automation logs
If your issue includes more than deployment hygiene," I will still start by stabilizing release infrastructure first because broken domains," bad SSL," missing env vars," and weak monitoring make every security fix harder to validate."
For founders who want speed without guesswork," this sprint gives you a clean handover checklist," production deployment," and monitoring so you know when something breaks instead of hearing it from customers."
References
- https://roadmap.sh/cyber-security
- https://roadmap.sh/api-security-best-practices
- https://roadmap.sh/code-review-best-practices
- https://firebase.google.com/docs/firestore/security/get-started
- https://supabase.com/docs/guides/database/postgres/row-level-security
---
Take the next step
If this is a problem in your product right now, here is what to do next:
- [Use the free Cyprian tools](/tools) - estimate cost, score app risk, check launch readiness, or pick the right service sprint.
- [Book a discovery call](/contact) - I will tell you honestly whether you need a sprint or if you can DIY the next step.
*Written by Cyprian Tinashe Aarons - senior full-stack and AI engineer helping founders rescue, launch, automate, and scale AI-built products.*
Cyprian Tinashe Aarons — Senior Full Stack & AI Engineer
Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.