fixes / launch-ready

How I Would Fix database rules leaking customer data in a Cursor-built Next.js AI-built SaaS app Using Launch Ready.

The symptom is usually ugly and obvious: one customer logs in and sees another customer's records, admin-only fields show up in the UI, or support gets...

How I Would Fix database rules leaking customer data in a Cursor-built Next.js AI-built SaaS app Using Launch Ready

The symptom is usually ugly and obvious: one customer logs in and sees another customer's records, admin-only fields show up in the UI, or support gets screenshots of data that should never have left the database. In an AI-built Next.js SaaS app, the most likely root cause is not "Next.js is broken", it is usually weak row-level rules, a missing tenant filter, or server code that trusts client input too much.

The first thing I would inspect is the data access path, not the UI. I want to see how the app authenticates users, how it resolves tenant or org IDs, and whether reads are happening through a public client, server action, API route, or service role key.

Triage in the First Hour

1. Check whether the leak is reproducible with two test accounts from different tenants. 2. Open browser devtools and inspect the network requests for any endpoint returning data without a tenant-scoped filter. 3. Review recent deploys and commits from Cursor-generated changes. 4. Inspect database rules, policies, triggers, and views for tables that contain customer data. 5. Confirm whether any server-side code uses an elevated secret key where it should not. 6. Check logs for unauthorized reads, unusual query volume, and requests missing auth context. 7. Review environment variables in the deployment platform for exposed secrets or wrong keys. 8. Verify whether caching or ISR is serving one user's response to another user. 9. Check Cloudflare or CDN caching rules if responses are cached at the edge. 10. Freeze new deploys until you know whether this is a policy issue or an application logic issue.

If I need a quick diagnostic command during triage, I usually start by looking for direct table access patterns and service-role usage:

grep -R "service_role\|from('.*')\|supabase.from\|prisma\|tenantId\|orgId" app src lib

That does not fix anything by itself. It just tells me where the app may be bypassing proper access control.

Root Causes

| Likely cause | What it looks like | How I confirm it | |---|---|---| | Missing row-level security | Any authenticated user can read rows across tenants | Inspect DB policies and test with two accounts | | Client-side trust of org ID | UI sends `orgId` from local state or URL and backend accepts it | Trace request payloads and compare against session claims | | Service role key used in user flows | App can read everything because backend runs with full privileges | Search env vars and server code for elevated keys | | Broken cache isolation | One user's JSON response is cached and reused for another user | Disable cache temporarily and compare responses across sessions | | Over-permissive views or joins | A safe table becomes unsafe through a view or joined relation | Review SQL views, functions, triggers, and grants | | Cursor-generated shortcut logic | Fast prototype code skipped auth checks on "temporary" endpoints that shipped to prod | Diff recent commits and inspect routes added during AI-assisted work |

The pattern I see most often is this: the founder built fast with Cursor, got something working, then copied a helper function across multiple routes without tightening authorization. That creates a product that feels live but behaves like a shared spreadsheet.

The Fix Plan

My rule here is simple: stop the leak first, then repair the architecture, then redeploy carefully.

1. Disable public access paths that are leaking data.

  • If there is an endpoint returning cross-tenant records, put it behind a temporary 403 until it is fixed.
  • If needed, turn off non-essential features for 24 hours rather than keep exposing customer data.

2. Lock down database access at the source.

  • Turn on row-level security for every customer-owned table.
  • Write policies so reads and writes require both authentication and tenant membership.
  • Remove any blanket allow policy that was added during prototyping.

3. Replace client-trusted tenant selection with server-trusted identity.

  • The backend should derive `user_id` and `tenant_id` from the session token or verified server session.
  • Never trust an `orgId` passed only from the browser.

4. Audit all server routes and actions.

  • Check API routes, server actions, background jobs, cron handlers, webhook handlers, and admin screens.
  • Any route using elevated credentials must enforce explicit authorization before reading customer data.

5. Fix caching behavior.

  • Mark sensitive responses as private or no-store where appropriate.
  • Make sure per-user content cannot be cached at a shared layer like CDN or edge cache.

6. Tighten secrets handling.

  • Rotate exposed secrets immediately if there is any chance they were leaked into logs or client bundles.
  • Move environment variables out of frontend-exposed scopes unless they are truly public.

7. Add least-privilege service design.

  • Use normal user credentials for normal reads and writes.
  • Reserve service-role access only for tightly controlled backend jobs that need it.

8. Add observability before re-enabling traffic fully.

  • Log denied access attempts without logging sensitive payloads.
  • Track which endpoint returns which tenant's data so you can prove isolation works after release.

Here is the sequence I would follow in practice:

1. Patch policies in staging first. 2. Run two-account tests against every customer-facing endpoint. 3. Deploy to production behind a feature flag if possible. 4. Verify no cross-tenant reads in logs for at least 30 minutes under real traffic. 5. Re-enable disabled features only after checks pass.

If this was my sprint, I would keep changes small enough to review in one sitting. Big refactors are risky here because they create new ways to leak while trying to fix old ones.

Regression Tests Before Redeploy

I would not ship this fix without proof that isolation works under realistic conditions.

  • Create two test users in different tenants with overlapping record shapes.
  • Confirm User A cannot read User B's records through:
  • page loads
  • API routes
  • server actions
  • search endpoints
  • export/download endpoints
  • Confirm unauthorized requests return 401 or 403 consistently.
  • Confirm authorized users only see their own rows even when they manipulate query params manually.
  • Confirm admin-only views are hidden from standard users both in UI and backend response shape.
  • Confirm cached pages do not swap content between sessions after refreshes or hard reloads.
  • Confirm logs do not contain raw PII or full customer payloads.

Acceptance criteria I would use:

  • Cross-tenant read rate: 0 out of 100 test requests.
  • Unauthorized endpoint responses: 100 percent blocked with correct status codes.
  • Sensitive response caching: disabled or scoped correctly for all protected routes.
  • Test coverage target: at least 80 percent on auth-critical data access code paths.

I also want one manual exploratory pass before release:

  • Log in as three roles: owner, member, outsider.
  • Try direct URL access to every customer screen.
  • Change IDs in query strings and verify nothing leaks back.

Prevention

This class of bug comes back when teams treat security as a final checklist item instead of part of product behavior.

What I would put in place:

  • Code review gate:
  • Every change touching auth, queries, policies, or webhooks gets senior review first.
  • No merged "temporary" bypasses into production branches.
  • Security guardrails:
  • Default-deny policies on all customer tables.
  • Least privilege on service keys and database roles.
  • Secret rotation after any suspected exposure.
  • QA guardrails:
  • Add automated multi-tenant tests to CI before deploys go live.
  • Include negative tests for unauthorized reads on every new feature touching customer data.
  • UX guardrails:
  • Show clear permission errors instead of vague blank states so users do not retry broken flows endlessly.
  • Make account switching obvious if your product supports multiple organizations per login.
  • Performance guardrails:
  • Keep auth checks close to data access so you do not create slow fallback logic that developers later bypass "for speed".
  • Monitor p95 latency on protected endpoints; if it jumps above 400 ms after adding checks, profile before removing controls.

I also recommend alerting on suspicious patterns:

  • repeated denied reads,
  • spikes in export activity,
  • sudden increases in requests missing session context,
  • unusual admin route hits from standard users.

That gives you business-level warning before support tickets become a public incident.

When to Use Launch Ready

Launch Ready fits when the product works but cannot be trusted yet in production because infra and release hygiene are still shaky. If your Next.js app has leaking rules plus messy deployment setup, I would use this sprint to stabilize domain routing, email deliverability, SSL, Cloudflare protection, secrets handling, monitoring, and handover in one tight window.

That includes DNS setup, redirects, subdomains, Cloudflare config, SSL issuance, caching rules where appropriate, DDoS protection basics, SPF/DKIM/DMARC email setup, production deployment support, environment variables cleanup, secret handling review, uptime monitoring setup, and a handover checklist.

What you should prepare before booking:

  • Repository access with deploy permissions
  • Database admin or policy-edit access
  • Hosting account access
  • Domain registrar access
  • Email provider access
  • A list of affected pages/endpoints
  • Two test accounts from separate tenants
  • Any recent incident screenshots or support tickets

If your app already leaks customer data today but otherwise has product-market fit signals such as active users or paid pilots going cold because of trust issues around launch stability matters more than redesigning features first. Fix the foundation so you stop bleeding customers while continuing to ship safely.

References

1. https://roadmap.sh/cyber-security 2. https://roadmap.sh/api-security-best-practices 3. https://roadmap.sh/code-review-best-practices 4. https://supabase.com/docs/guides/database/postgres/row-level-security 5. https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions

---

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.*

Next steps
About the author

Cyprian Tinashe AaronsSenior Full Stack & AI Engineer

Cyprian helps founders rescue, secure, deploy, and automate AI-built apps with production-grade engineering, launch systems, and AI integration.