How I Would Fix database rules leaking customer data in a React Native and Expo internal admin app Using Launch Ready.
The symptom is simple and expensive: an internal admin app is showing customer records that the user should never see. In practice, this usually means the...
How I Would Fix database rules leaking customer data in a React Native and Expo internal admin app Using Launch Ready
The symptom is simple and expensive: an internal admin app is showing customer records that the user should never see. In practice, this usually means the database rules are too broad, the client is querying directly with weak auth context, or row-level access is being bypassed by a bad environment setup.
The first thing I would inspect is the exact path from login to data fetch. I want to know which account is signed in, which token the app sends, which collection or table is queried, and whether the leak happens in dev, staging, or production.
Launch Ready fits here because this is not just a UI bug. This is a production access-control problem that can expose customer data, trigger compliance issues, and create support and trust damage in hours.
Triage in the First Hour
1. Confirm the scope of exposure.
- Check whether the leak affects all users or only specific roles.
- Verify if it is limited to one screen, one query, or all admin views.
- Compare behavior across iOS, Android, Expo Go, and production builds.
2. Inspect auth state in the app.
- Confirm the current user ID, role claims, tenant ID, and session expiry.
- Check whether anonymous or stale sessions are still able to load data.
- Review any custom token parsing or cached auth state.
3. Review database access logs.
- Look for unexpected reads on customer tables or collections.
- Identify which service account, API key, or user token performed the reads.
- Check for spikes in read volume or repeated requests from one device.
4. Audit environment variables and build config.
- Verify production keys are not mixed with test keys.
- Confirm Expo config values are correct for each build profile.
- Check whether a public client key was used where a server-only key was required.
5. Inspect recent changes.
- Review the last 5 commits touching auth, data fetching, role checks, or schema rules.
- Look at any recent merge from AI-generated code without review.
- Search for "allow read: if true", temporary debug code, or disabled guards.
6. Check admin screens and API calls.
- Open every high-risk screen: customer list, detail page, search results, export flow.
- Confirm filters are applied on the server side, not only in React Native state.
- Test whether direct navigation to a record ID bypasses tenant filtering.
7. Freeze risky paths if needed.
- Disable exports, bulk download endpoints, and unrestricted search until rules are fixed.
- If exposure is active, rotate credentials before shipping any hotfix.
## Quick diagnosis commands I would run npx expo start --clear grep -R "allow read\|public\|admin\|role\|tenant" .
Root Causes
1. Over-permissive database rules
- Common pattern: rules allow any authenticated user to read all rows.
- How I confirm it: review rule expressions against real user roles and test with two different accounts.
2. Missing tenant isolation
- Common pattern: queries filter by tenant only in the UI, but not in the database layer.
- How I confirm it: replay the same query with another tenant ID removed and see if records still return.
3. Client-side trust instead of server-side enforcement
- Common pattern: the app assumes hidden screens mean hidden data.
- How I confirm it: inspect network calls and verify whether raw endpoints return data without server checks.
4. Wrong environment or secret handling
- Common pattern: production app points at a staging backend or uses a shared key with broad access.
- How I confirm it: compare runtime env values in build logs and device logs against expected production settings.
5. Broken role claims or stale sessions
- Common pattern: users keep old admin claims after downgrade or logout does not clear tokens properly.
- How I confirm it: sign in as different roles on fresh installs and compare returned permissions.
6. Direct object access without authorization checks
- Common pattern: detail pages fetch by record ID alone and never verify ownership or tenant membership.
- How I confirm it: request another customer's record ID through deep link handling or direct API call behavior inside normal app flows.
The Fix Plan
I would fix this in layers so we do not trade one leak for another.
First, I would stop the bleeding. If exposure is active, I would temporarily disable affected reads behind a feature flag or narrow them to verified admin roles only. That buys time without forcing a full app shutdown.
Second, I would move authorization enforcement into the database rules or backend API layer. The rule should check identity plus role plus tenant membership every time, not just once during login. UI hiding is not security.
Third, I would replace broad queries with scoped queries. Every customer read should include an explicit tenant filter and should fail closed if tenant context is missing. If there is any ambiguity about ownership, return nothing rather than guessing.
Fourth, I would tighten secrets and build separation. Production keys belong only in production builds, staging keys belong only in staging builds, and anything sensitive must be rotated if there was even a chance of exposure. For an internal admin app built with Expo, this means checking EAS build profiles carefully and removing secrets from client bundles where possible.
Fifth, I would add server-side validation for every sensitive action:
- list customers
- view customer detail
- export CSV
- update billing fields
- impersonate support flows
Sixth, I would add logging that helps me detect future leaks without exposing customer data in logs. Log access decisions, role checks failed/succeeded counts, request IDs, and tenant IDs only when safe.
My preferred order is: 1. Lock down access rules 2. Rotate exposed secrets 3. Patch client queries 4. Add tests 5. Redeploy to staging first 6. Promote to production after verification
- DNS and deployment sanity check
- SSL and Cloudflare verification
- secret audit
- production rule fix
- monitoring setup
- handover checklist
Regression Tests Before Redeploy
I would not ship this fix until these checks pass:
1. Role-based access tests
- Admin can see permitted records only.
- Non-admin cannot see restricted records.
- Suspended users cannot fetch anything sensitive.
2. Tenant isolation tests
- User from Tenant A cannot fetch Tenant B records by list view or direct ID lookup.
- Empty tenant context returns zero records.
3. Auth edge cases
- Expired session gets rejected cleanly.
- Logged-out user sees no cached sensitive data after restart.
- Fresh install behaves differently from an old cached install only where expected.
4. Network inspection checks
- No endpoint returns full customer tables without authorization headers checked server side.
- No sensitive fields appear in unauthenticated responses.
5. UI safety checks
- Loading states do not flash restricted data before redirecting away.
- Empty states do not reveal record counts that should be hidden.
- Error messages do not disclose schema details or internal IDs unnecessarily.
6. Release verification on device
- Test on one iPhone simulator/device and one Android simulator/device.
- Test production build generated by EAS or your actual release pipeline.
- Confirm no debug-only flags remain enabled.
Acceptance criteria I would use:
- 0 unauthorized records visible across 2 roles and 2 tenants
- 100 percent of sensitive endpoints enforce auth server side
- 0 critical findings in manual QA before release
- p95 list fetch under 500 ms after caching and indexing are verified
Prevention
I would put guardrails around this so it does not come back next week.
Security guardrails:
- Require code review on any change touching auth or data access.
- Reject broad read rules unless there is an explicit business case documented.
- Rotate secrets quarterly and immediately after any suspected exposure.
- Use least privilege for service accounts and API keys.
QA guardrails:
- Add regression tests for every sensitive screen before merging.
- Keep a small set of real-world test accounts for admin, support, viewer, and suspended states.
- Run one manual smoke test on each release candidate using production-like data shape but sanitized content.
Monitoring guardrails:
- Alert on unusual read spikes by table/collection/tenant within 15 minutes.
- Log denied authorization attempts separately from successful reads.
- Track crashes plus unauthorized response rates together so security bugs do not hide behind "normal" errors.
UX guardrails:
- Show clear permission errors instead of silently failing screens that invite repeated retries.
- Avoid caching sensitive lists longer than needed on shared devices used by staff teams.
- Make logout fully clear local state so old records do not linger after role changes.
Performance guardrails:
- Index tenant ID plus commonly filtered fields so secure queries stay fast enough to use everywhere instead of being bypassed "for speed".
- Watch p95 latency on list pages; if it climbs above 700 ms internally admins will start asking for unsafe shortcuts again.
When to Use Launch Ready
Use Launch Ready when you need me to fix this fast without turning your product into a science project again later.
This sprint makes sense if you already have:
- an Expo app running somewhere close to production,
- a real backend or database,
- at least one admin workflow that must stay live,
- concern about leaked customer data,
- pressure to deploy within 48 hours instead of waiting weeks for a full rebuild.
What you should prepare before booking:
- current repo access,
- Expo/EAS credentials,
- database console access,
- Cloudflare/DNS access,
- production domain details,
- list of roles and what each role should see,
- 3 example users per role,
- screenshots of the broken screens,
- notes on when you first noticed the leak,
- any compliance concerns like GDPR or SOC 2 controls.
- domain,email,and Cloudflare checks,
- SSL verification,
- deployment cleanup,
- secrets review,
- monitoring setup,
- redirect sanity checks,
- handover checklist,
all delivered in 48 hours so you can ship with less risk of another exposure event tomorrow morning instead of hoping nobody notices today.
References
1. https://roadmap.sh/api-security-best-practices 2. https://roadmap.sh/code-review-best-practices 3. https://roadmap.sh/qa 4. https://docs.expo.dev/ 5. https://cloudflare.com/learning/ssl/what-is-an-origin-certificate/
---
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.