Plugging the Multi-Tenant Leak: Enforcing PostgreSQL RLS to Prevent Cross-Account Data Access
How a missing tenant_id filter in a Supabase/PostgreSQL SaaS application allowed Company A users to manipulate API URLs (IDOR Vulnerability) to inspect Company B’s confidential invoices, and how we enforced database-level Row Level Security (RLS) in 48 hours.
1. Executive Summary & Vulnerability Discovery
A B2B SaaS company offering invoicing and financial workflow software built on Supabase & PostgreSQL contacted HawkInspect Pro during a pre-funding enterprise CTO security evaluation.
During automated penetration testing, an enterprise client discovered an Insecure Direct Object Reference (IDOR) flaw: authenticated users from Company A could change the invoice ID in the API URL (e.g. from /api/invoices/inv_1001 to /api/invoices/inv_1002) and inspect private billing records, customer names, and bank details belonging to Company B.
Multi-Tenant Database Reality:Filtering by tenant_id in JavaScript/TypeScript API routes works until a developer forgets the WHERE clause in a single endpoint. Database-level PostgreSQL Row-Level Security (RLS) guarantees complete tenant isolation regardless of code bugs.
Concerned about multi-tenant data leaks in your SaaS?
We perform line-by-line PostgreSQL RLS policy audits and API middleware tenant isolation testing in 48 hours.
2. Quantifying the Cross-Account Data Leak Risk
Impact of the IDOR Multi-Tenant Leak
- Cross-Tenant Data Exposure: 100% of tenant tables lacked database-level Row Level Security (RLS) policies.
- SOC2 & GDPR Compliance Failure: Unisolated data access violated SOC2 Type II Trust Principles and GDPR data confidentiality requirements, threatening enterprise customer contracts.
- Systemic Human Error Risk: Relying on application-level
WHERE tenant_id = req.user.tenantIdlogic meant any new developer could accidentally introduce a data leak.
3. Vulnerable API Endpoint & Missing RLS
The original Node.js / Supabase route queried the database directly by invoice ID without enforcing or verifying tenant ownership at either the route or database engine level:
4. Anatomy of the IDOR Cross-Tenant Exploitation
An attacker authenticated as User X from Tenant A sends a legitimate HTTP GET request. By substituting the UUID parameter in the URL with an invoice ID belonging to Tenant B, the Supabase client returns Tenant B's raw database record because the table lacked PostgreSQL RLS policies and the endpoint lacked tenant verification.
5. Enforcing PostgreSQL Row Level Security (RLS)
HawkInspect Pro deployed a mandatory PostgreSQL Migration script enforcing RLS policies across all tenant tables. PostgreSQL now extracts tenant_id directly from the cryptographically signed JWT token:
6. Automated API Middleware Tenant Isolation Testing
To guarantee zero regressions in future deployments, we built an automated API Middleware integration test suite. The test runner spawns mock users from Tenant A and Tenant B, executing cross-tenant requests across all API routes to verify HTTP 403 Forbidden responses.
7. SOC2 & GDPR Compliance Impact
Zero Vulnerabilities
All multi-tenant API routes verified with 0 cross-tenant data leaks.
SOC2 & GDPR Audit Passed
Passed formal enterprise security due diligence and data isolation controls.
48-Hour Turnaround
Complete database migration, RLS policies, and test suite shipped in 48h.
48-Hour Multi-Tenant Security & PostgreSQL RLS Audit
Protect your SaaS from cross-tenant data leaks, IDOR flaws, and compliance failures. Our principal security engineers audit your database policies and API routes in 48 hours.
9. Interactive Multi-Tenant Security Diagnostic
MULTI-TENANT SECURITY CHECKLIST WE AUDIT
CRITICAL MULTI-TENANT LEAK RISK
High vulnerability to IDOR cross-tenant data access. Urgent PostgreSQL RLS policy enforcement recommended.
11. Multi-Tenant Security FAQ
12. What Was Actually Wrong & The Question Worth Asking
Not PostgreSQL engine speed. Not Supabase API limits. Not Next.js router performance.
The vulnerability was a Missing PostgreSQL Row Level Security (RLS) Policy that allowed cross-account data access (IDOR) via simple URL parameter edits.
WHERE id = req.params.id (No RLS)
Company A user can edit the ID in URL and inspect Company B private invoices.
CREATE POLICY ... USING (tenant_id = auth.jwt()->>'tenant_id')
Database engine enforces tenant isolation automatically. 0 Leaks.
Database-Level RLS Policy Enforcement
JWT Tenant Claim Verification
Automated Isolation Test Suite
If an authenticated user changes tenant_id or resource ID in an API URL today, does PostgreSQL block the request with RLS or leak private customer data?
Get Your Multi-Tenant Database Security Audited
Talk directly with our Principal Security Auditor. We'll inspect your PostgreSQL RLS policies, Supabase claims, and API endpoints in 48 hours.