How I Would Fix database rules leaking customer data in a Bolt plus Vercel automation-heavy service business Using Launch Ready.
The symptom is usually simple: one customer can see another customer's records, emails, invoices, automations, or internal notes. In an automation-heavy...
How I Would Fix database rules leaking customer data in a Bolt plus Vercel automation-heavy service business Using Launch Ready
The symptom is usually simple: one customer can see another customer's records, emails, invoices, automations, or internal notes. In an automation-heavy service business, that turns into support tickets, broken trust, and possible privacy exposure fast.
The most likely root cause is weak row-level access control in the database layer, often combined with client-side queries that assume the app will only ever ask for "its own" data. The first thing I would inspect is the exact path from browser to database: auth claims, query filters, database rules or policies, and whether Vercel serverless functions are accidentally using an over-privileged secret key.
Triage in the First Hour
1. Check whether the leak is active right now.
- Open two test accounts with different tenants or customers.
- Compare what each account can read in the UI and via any API endpoints.
- Confirm whether the leak is limited to one table or spans multiple objects like jobs, messages, automations, billing, and logs.
2. Inspect recent deployments in Vercel.
- Look at the last 3 builds and deployment diffs.
- Check whether a new environment variable, server action, or route handler was added.
- Confirm if a change switched from scoped user queries to admin-level database access.
3. Review auth and session behavior.
- Verify how user identity is passed into Bolt-generated frontend code.
- Check JWT claims, session cookies, and any middleware that sets tenant IDs.
- Look for missing tenant checks on server-side endpoints.
4. Audit database policies or rules.
- Read all row-level security policies or equivalent access rules on sensitive tables.
- Confirm whether there are default allow rules, broad selects, or missing update/delete restrictions.
- Check if joins expose related customer data through a less protected table.
5. Inspect secrets and environment variables in Vercel.
- Make sure no service-role key is exposed to client code.
- Confirm production and preview environments do not share unsafe secrets.
- Check for any leaked keys in build logs or pasted into Bolt prompts.
6. Review logs and monitoring.
- Search for requests returning unusually large result sets.
- Look for 200 responses on endpoints that should have been denied.
- Note any spikes in support volume after the last deploy.
7. Freeze risky changes until containment is clear.
- Pause new releases from Bolt-generated changes.
- Disable write paths if needed before you keep leaking more data.
- If necessary, put the app into a limited maintenance mode for 1 to 2 hours.
-- Example diagnostic check for policy coverage select tablename, policyname from pg_policies where schemaname = 'public' order by tablename, policyname;
Root Causes
1. Missing row-level security on sensitive tables.
- Confirmation: authenticated users can query rows without tenant filters.
- I would test this by comparing results across two accounts with different org IDs.
2. Over-broad allow policies.
- Confirmation: policies use conditions like `true`, `auth.uid() is not null`, or permissive role checks without tenant scoping.
- I would inspect every select policy on customer-facing tables and look for blanket access.
3. Serverless functions using admin credentials for normal reads.
- Confirmation: Vercel routes or server actions call the database with a service key instead of a user-scoped session.
- I would trace one request end-to-end and verify which credential reaches the database.
4. Tenant ID not enforced in every query path.
- Confirmation: some pages filter by `org_id`, but export jobs, search endpoints, webhooks, or background tasks do not.
- I would grep for every table access path and compare query filters across frontend and backend code.
5. Join leakage through related tables or views.
- Confirmation: a safe table joins to invoices, contacts, notes, or automation history that has weaker protection.
- I would inspect views and foreign-key relationships because leaks often happen there instead of on the main table.
6. Preview environment mirrors production data too closely.
- Confirmation: preview deployments can read real customer records through shared credentials or copied env vars.
- I would check whether preview builds have production secrets or unrestricted database access.
The Fix Plan
My goal here is to stop exposure first, then make the access model boring and explicit. I would not try to patch this with frontend filtering alone because that only hides data after it has already been fetched.
1. Contain immediately if exposure is confirmed.
- Disable public endpoints that return sensitive records without authorization checks.
- Rotate any exposed secrets if there is even a chance they were logged or copied into Bolt prompts.
- If needed, temporarily block non-admin reads until policies are fixed.
2. Define the tenancy model clearly.
- Decide whether access is per user, per organization, or per workspace.
- Put that decision into one source of truth: auth claims plus database rules plus server-side enforcement.
3. Tighten database rules table by table.
- Turn on row-level security where it is missing on customer data tables.
- Add select policies that require matching `org_id` or ownership fields on every sensitive table.
- Add insert/update/delete rules so users cannot move records across tenants.
4. Remove unsafe direct reads from client code where needed.
- For highly sensitive objects like invoices, contact lists, internal notes, and automation payloads, move reads through server routes with explicit authorization checks if client-side access cannot be trusted yet.
- This reduces blast radius while you clean up the model properly.
5. Replace broad secrets with least-privilege credentials.
- Keep service-role access only in trusted server-only paths that truly need it.
- Use separate credentials for production and preview environments so one mistake does not expose everything everywhere.
6. Patch joins and views before redeploying anything else.
- Every view must obey the same tenant rule as base tables unless it is intentionally public data only।
- If a join leaks child records from another tenant, fix both sides of the relationship.
7. Add explicit authorization checks in Vercel routes and server actions.
- Validate session identity before querying anything sensitive।
- Reject requests early if tenant context is missing or mismatched।
8. Ship in small steps with rollback ready。
- Deploy policy changes first in staging।
- Then deploy code changes behind a feature flag if possible।
- Keep one rollback point per layer: database policy version plus app deployment version۔
Regression Tests Before Redeploy
I would not redeploy until these checks pass against staging with at least two separate test tenants. The acceptance bar should be strict because privacy bugs are expensive to recover from later.
1. Cross-tenant read test
- Tenant A cannot read Tenant B's customers, jobs, messages, invoices, automations, or logs।
- Acceptance criteria: 0 unauthorized rows returned across all tested endpoints।
2. Cross-tenant write test
- Tenant A cannot update or delete Tenant B's records।
- Acceptance criteria: all unauthorized writes fail with 401 or 403 style responses as designed।
3. Service-key containment test
- No client bundle contains service-role secrets۔
- Acceptance criteria: secret scan returns 0 matches in browser code and public assets।
4. Preview deployment safety test
- Preview environments use isolated credentials or sanitized data۔
- Acceptance criteria: preview cannot reach production customer rows directly۔
5. Join leakage test
- Queries involving joins and views return only rows belonging to the current tenant۔
- Acceptance criteria: no related-table leakage in at least 10 representative scenarios۔
6. Negative auth tests
- Missing session, expired session, tampered token, wrong org ID, stale membership۔
- Acceptance criteria: all fail closed with clear error handling۔
7. Smoke test for automation flows
- Run one end-to-end job from lead capture to email follow-up to dashboard logging۔
- Acceptance criteria: correct tenant attribution persists through every step۔
8. Observability check
- Confirm logs capture denied requests without storing raw personal data۔
- Acceptance criteria: no sensitive payloads appear in application logs。
Prevention
I would put guardrails around three layers: code review, security controls, and operational monitoring۔ That way this does not come back when someone ships a quick Bolt change at midnight before a launch call۔
| Area | Guardrail | What it prevents | |---|---|---| | Code review | Require every sensitive query to show tenant scoping | Silent cross-account reads | | Database | Default-deny RLS on all customer tables | New tables shipping open | | Secrets | Separate prod and preview env vars | Preview leaks reaching prod | | Monitoring | Alert on unusually large reads per user | Data scraping patterns | | QA | Add cross-tenant tests to CI | Regressions after future deploys | | UX | Show loading/error states clearly when auth fails | Confusing broken onboarding |
Other controls I would add:
- Log denied access attempts without storing full personal data unnecessarily。
- Review dependency updates weekly because auth helpers and ORM wrappers can change behavior quietly。
- Keep p95 API latency under 300 ms for normal dashboard reads so teams do not get tempted to bypass secure paths with shortcuts。
- Run monthly permission audits on all admin roles。
- Document which endpoints may use elevated credentials and why。
When to Use Launch Ready
Launch Ready fits when you need this fixed fast without turning it into a week-long engineering fire drill.
I would use this sprint when:
- Your Bolt build works locally but breaks under real traffic۔
- Vercel deployment exists but secrets、redirects、or monitoring are incomplete۔
- You suspect customer data exposure but need a senior engineer to isolate the issue quickly۔
- You want one clean production handover instead of piecemeal fixes across tools۔
What you should prepare before booking: 1. Access to Vercel、database、Cloudflare、and domain registrar。 2. A list of all roles、tenants、and sensitive tables。 3. Any recent screenshots of leaked records or support complaints۔ 4. A short note on what "customer" means in your app: person、company、or workspace。 5. One point of contact who can approve emergency changes within hours。
My recommendation is simple: fix the access model first,then launch hardening second。If you try to polish UX before closing the leak,you will just make an unsafe product look better。
References
1. Roadmap.sh API Security Best Practices https://roadmap.sh/api-security-best-practices
2. Roadmap.sh Cyber Security https://roadmap.sh/cyber-security
3. Roadmap.sh QA https://roadmap.sh/qa
4. Supabase Row Level Security docs https://supabase.com/docs/guides/database/postgres/row-level-security
5. Vercel Environment Variables docs https://vercel.com/docs/projects/environment-variable-management
---
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.