How I Would Fix database rules leaking customer data in a React Native and Expo AI-built SaaS app Using Launch Ready.
The symptom is usually not subtle. A founder notices one user can see another user's records, support gets a screenshot of private data, or a test account...
How I Would Fix database rules leaking customer data in a React Native and Expo AI-built SaaS app Using Launch Ready
The symptom is usually not subtle. A founder notices one user can see another user's records, support gets a screenshot of private data, or a test account suddenly shows real customer rows in the mobile app.
The most likely root cause is bad authorization at the database layer, not the React Native UI. In an AI-built Expo SaaS app, I would first inspect the database rules, auth claims, and the exact query path the app uses to read customer data.
If this is leaking production customer data, I treat it as a security incident first and a bug second. The business risk is immediate: trust loss, possible GDPR exposure, support load, and a launch delay while you rebuild confidence in the product.
Triage in the First Hour
1. Check whether leakage is happening in production or only in staging.
- Confirm which environment the affected build is pointed at.
- Verify API base URLs, project IDs, and backend keys in the Expo config.
2. Inspect recent auth logs and access patterns.
- Look for unexpected reads from the same user session.
- Check whether anonymous users or expired tokens are still getting data.
3. Review the database rules or row-level security policies.
- Find tables that store customer profiles, orders, messages, files, or billing data.
- Confirm whether read access is scoped by `user_id`, `org_id`, or tenant ID.
4. Audit the client screens that fetch sensitive data.
- Search for direct table reads from the app.
- Identify any fallback queries that return too much data when filters fail.
5. Check recent deploys and AI-generated code changes.
- Review commits from Lovable, Cursor, Bolt, or similar tools.
- Look for policy changes, schema edits, or "temporary" admin bypasses.
6. Verify secrets and service keys.
- Confirm no privileged key was shipped inside the Expo bundle.
- Check whether any admin credential is being used on-device.
7. Reproduce with two separate test accounts.
- Account A should never see Account B's rows.
- Test both fresh login and token refresh flows.
8. Inspect monitoring and error logs.
- Look for 401s turning into silent fallback reads.
- Check if missing auth claims are causing broad queries instead of blocked access.
A simple first-pass command I would run during diagnosis:
grep -R "select.*from\|getDocs\|supabase\|firebase\|org_id\|user_id" src app lib
That tells me fast whether the app is querying sensitive data directly and where to focus the policy review.
Root Causes
| Likely cause | How I confirm it | |---|---| | Missing row-level security or equivalent policy | Querying as two different users returns the same rows or unrestricted rows | | Client uses an admin or service key | The Expo bundle or env config contains privileged credentials | | Auth token is not attached consistently | Some requests work without user context because fallback logic returns default data | | Tenant filter is missing from queries | Code reads by table name only instead of `user_id` or `org_id` | | Overly broad database policy | Policy allows `select` on all authenticated users instead of only owners | | AI-generated schema or rule change broke isolation | Recent commit changed rules faster than tests could catch it |
1. Missing row-level security
This is common when founders move fast with Supabase, Firebase wrappers, Postgres APIs, or custom backend endpoints. The app works because data loads, but every authenticated user can see too much.
I confirm it by comparing what user A and user B can fetch from the same endpoint or table. If both can read each other's records without explicit ownership checks, that is your issue.
2. Service key shipped to the client
This is a serious mistake because it turns the mobile app into an admin console if someone extracts the bundle or inspects network calls. In React Native and Expo projects built quickly with AI tools, this happens more often than founders expect.
I confirm it by checking environment variables exposed to the app bundle and any config files committed to git. If a secret belongs on a server but exists in Expo client code, I assume compromise risk until proven otherwise.
3. Bad tenant scoping in queries
Sometimes rules are correct but queries are wrong. For example, a query may filter by `status = active` but forget `org_id = currentOrgId`, so it returns every active record across tenants.
I confirm it by reading each sensitive query path end to end. If tenant scope is added only in UI state but not enforced at backend access control level, I do not trust it.
4. Auth state race condition
Expo apps often render before auth finishes loading. If the code fetches customer data before token validation completes, it may hit an unauthenticated fallback path that returns broad results or cached content.
I confirm it by testing cold start, token refresh, logout/login loops, and slow network conditions. If leakage appears only during startup or after resume from background, this is likely part of it.
5. Over-broad policy written for convenience
AI-built apps often get policies like "allow read if authenticated" because that unblocks demos quickly. That pattern becomes dangerous once real customers sign up under separate accounts or organizations.
I confirm it by reading policy definitions line by line and checking whether they enforce ownership at row level. Authentication alone is not authorization.
The Fix Plan
First I would freeze risky deploys and stop any further schema or policy changes until isolation is restored. If customer data has already leaked across accounts, I would temporarily disable affected read paths rather than keep shipping blind updates.
Then I would fix this in a strict order:
1. Lock down database access first.
- Enforce row-level security or equivalent authorization at the table level.
- Require `user_id` or `org_id` matching on every sensitive table.
- Deny by default and open only specific safe reads.
2. Remove privileged credentials from mobile code.
- Move all admin operations behind server-side endpoints.
- Rotate any exposed keys immediately.
- Rebuild secrets handling so Expo only sees public configuration values.
3. Patch every sensitive query path.
- Add explicit tenant filters to reads and writes.
- Make sure list screens cannot load cross-tenant rows even if UI state breaks.
- Do not rely on front-end filtering for security.
4. Fix auth flow ordering in React Native.
- Block protected queries until auth state resolves fully.
- Show loading states instead of firing unsafe fallback requests.
- Clear cached user data on logout and account switch.
5. Add server-side validation where possible.
- Verify ownership before returning files, messages, invoices, profiles, or analytics rows.
- Treat client-supplied IDs as untrusted input.
- Reject requests that do not match session identity.
6. Rotate secrets and invalidate sessions if exposure occurred.
- Rotate DB keys, API keys, email provider keys if touched indirectly through logs or admin flows.
- Force re-authentication for active sessions if there is any chance tokens were abused.
7. Add monitoring before redeploying widely.
- Alert on cross-tenant access attempts.
- Log denied reads with enough context to investigate without storing sensitive payloads unnecessarily.
My preference here is boring on purpose: fix authorization at the backend first, then repair client behavior second. Anything else risks hiding the leak instead of closing it.
Regression Tests Before Redeploy
Before shipping anything back to production, I want evidence that cross-account access is blocked under realistic conditions.
Required QA checks
- User A cannot read User B's records through any screen or API call.
- Anonymous requests receive 401 or empty safe responses where appropriate.
- Expired tokens do not fall back to broad reads.
- Logout clears cached private data from memory and local storage where used.
- Account switching does not show previous tenant content for even one frame after login change.
- Sensitive list views still work under slow network conditions without unsafe fallback behavior.
Acceptance criteria
- 0 cross-tenant leaks in manual testing across at least 2 separate accounts and 3 protected screens.
- 100 percent of sensitive tables have explicit authorization rules reviewed before merge.
- No privileged secret exists in Expo client-side config files or bundled env output.
- All protected endpoints return correct denial behavior for unauthorized access attempts.
- Security regression tests run in CI before release tagging.
Edge cases I would test
- Fresh install with no cached session
- Token refresh during background resume
- Network timeout while loading protected data
- Switching between two orgs on one device
- Deep link directly into a private screen
- Offline cache rehydration after logout
If possible, I would also add automated checks that simulate two tenants against staging so this does not become a manual-only security habit again.
Prevention
The long-term fix is process plus guardrails. Without them, AI-built apps tend to repeat authorization mistakes because speed hides risk until customers find it first.
What I would put in place:
- Security review checklist for every release:
- auth
- authorization
- secret handling
- CORS where relevant
- logging hygiene
- dependency updates
- Code review rule:
- no merge if sensitive tables lack explicit tenant scoping
- no merge if client code contains server secrets
- no merge if fallback logic returns broader datasets on failure
- Monitoring:
- alerts for unusual read volume per account
- alerts for denied access spikes
- uptime monitoring plus error tracking tied to release versions
- UX guardrails:
- loading states until auth resolves
- clear empty states instead of stale cached content
- visible account switching confirmation when multiple tenants exist
- Performance guardrails:
- keep protected screens fast enough that developers do not add unsafe shortcuts later
- target p95 API latency under 300 ms for normal reads where practical
- keep mobile bundle size controlled so auth state does not lag behind rendering
For AI-built products specifically, I also want red-team style checks against prompt injection if any AI features touch customer records later on. If an assistant can retrieve private rows through tool use without strict permission checks, you have recreated this problem through another door.
When to Use Launch Ready
Launch Ready fits when you need me to stop risky deployment drift while making the product production-safe fast. It is especially useful if your leak came from messy launch plumbing around domain setup, environment variables, SSL confusion, Cloudflare misconfigurations, email authentication gaps like SPF/DKIM/DMARC issues impacting trust signals indirectly related to support workflows now using customer info).
It includes DNS setup, redirects,, subdomains,, Cloudflare,, SSL,, caching,, DDoS protection,, SPF/DKIM/DMARC,, production deployment,, environment variables,, secrets,, uptime monitoring,, and a handover checklist."
What you should prepare before booking:
- Access to your repo
- Access to hosting provider
- Database admin access with least privilege approved
- Domain registrar access
- Cloudflare access if already used
- Current build links for iOS and Android if applicable
- A short list of which tables contain customer data
- Any known incidents where users saw another user's information
If your issue includes broken deployment hygiene plus leaked data risk together, Launch Ready gives me enough room to stabilize launch infrastructure while we close off obvious exposure paths fast. If you need deeper product redesign afterward, I would split that into a second sprint instead of trying to cram everything into one rescue window.
References
https://roadmap.sh/cyber-security https://roadmap.sh/api-security-best-practices https://roadmap.sh/code-review-best-practices https://supabase.com/docs/guides/database/postgres/row-level-security https://docs.expo.dev/guides/environment-variables/
---
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.