What Is This Vulnerability
An RLS bypass on DELETE occurs when a table's delete policy allows users to remove rows they do not own. DELETE policies use a USING clause to determine which rows can be targeted for deletion. When this clause is set to true or lacks a proper ownership check, any user can delete any row, including rows belonging to other users or critical system data.
-- VULNERABLE: Any user can delete any row
CREATE POLICY "Allow deletes"
ON documents FOR DELETE
USING (true);
This is especially dangerous because DELETE operations are destructive and often irreversible without backups.
Why It's Dangerous
Unauthorized DELETE access enables catastrophic attacks:
- Mass data destruction: An attacker can delete all rows in a table with a single API call
- Targeted sabotage: Deleting specific users' data, orders, or content
- Denial of service: Removing critical configuration or reference data that the application depends on
- Cover tracks: Deleting audit logs, scan results, or activity records to hide malicious activity
- Business disruption: Removing products, inventory records, or customer data
Unlike other operations, DELETE causes permanent data loss. Even with Supabase's Point-in-Time Recovery, restoring data requires downtime and may result in losing recent legitimate changes.
# An attacker can wipe an entire table
curl -X DELETE 'https://YOUR_PROJECT.supabase.co/rest/v1/documents?id=gt.0' \
-H "apikey: YOUR_ANON_KEY" \
-H "Authorization: Bearer YOUR_ANON_KEY"
How to Detect
Review DELETE policies in the system catalog:
SELECT tablename, policyname, cmd, qual
FROM pg_policies
WHERE schemaname = 'public'
AND cmd = 'DELETE';
Any policy where qual is true or does not include an auth.uid() check is a finding. AuditYourApp tests DELETE access by attempting to delete a test row as an unauthorized user. You should also check whether tables with sensitive data have DELETE policies at all, since many tables should not allow client-side deletes.
How to Fix
Restrict DELETE policies to row owners, and consider whether client-side deletes should be allowed at all:
DROP POLICY "Allow deletes" ON documents;
-- Only owners can delete their own documents
CREATE POLICY "Users can delete own documents"
ON documents FOR DELETE
USING (auth.uid() = user_id);
For many tables, soft deletes are safer than hard deletes:
-- Instead of allowing DELETE, use a soft-delete pattern
ALTER TABLE documents ADD COLUMN deleted_at timestamptz;
-- No DELETE policy at all - use UPDATE instead
CREATE POLICY "Users can soft-delete own documents"
ON documents FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- Filter out soft-deleted rows in SELECT policies
CREATE POLICY "Users can view own active documents"
ON documents FOR SELECT
USING (auth.uid() = user_id AND deleted_at IS NULL);
For critical reference tables (roles, configuration, etc.), never create a DELETE policy. Let the service_role key handle deletions from Edge Functions when business logic requires it.
Scan your app for this vulnerability
AuditYourApp automatically detects security misconfigurations in Supabase and Firebase projects. Get actionable remediation in minutes.
Run Free ScanRelated
vulnerabilities
RLS Bypass: Unauthorized INSERT
Tables allow unauthenticated or cross-user inserts due to missing or overly permissive INSERT policies.
vulnerabilities
RLS Bypass: Unauthorized UPDATE
Tables allow unauthenticated or cross-user updates due to missing or overly permissive UPDATE policies.
vulnerabilities
Missing Row Level Security Policy
Tables without RLS are fully exposed to any user with the anon key, allowing unrestricted read and write access to all rows.