HIGH auth bypasssupabase

Auth Bypass on Supabase

How Auth Bypass Manifests in Supabase

Auth bypass in Supabase typically occurs when developers rely on client-side row-level security (RLS) policies without properly enforcing them on the server side. Supabase's architecture creates several unique vulnerability patterns:

Client-Side Policy Reliance

// Vulnerable: client trusts RLS policies
const { data, error } = await supabase
  .from('users')
  .select('*')
  .eq('email', userEmail)

The above code assumes RLS policies will prevent unauthorized access, but if policies are misconfigured or missing, anyone can query any user's data. This is particularly dangerous because Supabase's client libraries don't enforce authentication at the library level.

Missing Row-Level Security

-- Vulnerable: no RLS policies defined
CREATE TABLE profiles (
  id UUID DEFAULT gen_random_uuid(),
  user_id UUID REFERENCES auth.users(id),
  email TEXT,
  PRIMARY KEY (id)
);

Without explicit RLS policies, Supabase tables default to public access. Even with auth enabled, unauthenticated requests can read/write data if policies aren't defined.

Service Role Key Exposure

// Vulnerable: service_role key in client
const supabase = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_SERVICE_ROLE_KEY // NEVER expose this client-side
);

Service role keys bypass all RLS policies and can access any data. Embedding these keys in client applications creates immediate auth bypass vulnerabilities.

Broken JWT Validation

// Vulnerable: trusting unverified JWT claims
const { data } = await supabase
  .from('orders')
  .select('*')
  .eq('user_id', decodedToken.user_id) // No verification

Attackers can forge JWT tokens with arbitrary claims if the application doesn't properly validate token signatures or expiration.

Cross-Tenant Data Leakage

-- Vulnerable: policies don't scope by tenant
CREATE POLICY "Users can view their own profiles"
  ON profiles
  FOR SELECT
  USING (true); -- Should be: USING (auth.uid() = user_id)

Multi-tenant applications often fail to scope policies by tenant ID, allowing users to access other tenants' data through simple ID manipulation.

Supabase-Specific Detection

Detecting auth bypass in Supabase requires both static analysis and runtime scanning. Here's how to identify these vulnerabilities:

Static Analysis Patterns

# Check for service_role key usage
grep -r "service_role" . --include="*.js" --include="*.ts" --include="*.json"

# Find missing RLS policies
supabase sql "SELECT schemaname, tablename FROM pg_tables WHERE schemaname = 'public' AND tablename NOT IN (
  SELECT tablename FROM pg_policies
)"

Runtime Testing with middleBrick

middleBrick's black-box scanning specifically tests Supabase auth bypass patterns:

# Scan Supabase endpoint
middlebrick scan https://your-project.supabase.co/api/v1/endpoint

# Scan with OpenAPI spec for deeper analysis
middlebrick scan --spec openapi.json https://your-project.supabase.co/api/v1/endpoint

The scanner tests for:

  • Missing or permissive RLS policies
  • Service role key exposure
  • JWT token manipulation vulnerabilities
  • Cross-tenant data access
  • Authentication bypass through parameter manipulation

Database-Level Detection

-- Find tables without RLS policies
SELECT 
  schemaname, 
  tablename, 
  (SELECT count(*) FROM pg_policies WHERE schemaname = pol.schemaname AND tablename = pol.tablename) as policy_count
FROM pg_tables pol
WHERE schemaname = 'public'
ORDER BY policy_count;

Network Traffic Analysis

# Test for auth bypass by removing auth headers
curl -H "Content-Type: application/json" \
  -H "apikey: $(SUPABASE_ANON_KEY)" \
  -X GET https://your-project.supabase.co/rest/v1/users

If this returns data without proper authentication, RLS policies are missing or misconfigured.

Supabase-Specific Remediation

Fixing auth bypass in Supabase requires a defense-in-depth approach. Here are specific remediation strategies:

Proper RLS Policy Implementation

-- Secure: properly scoped policies
CREATE POLICY "Users can view their own profiles"
  ON profiles
  FOR SELECT
  USING (auth.uid() = user_id);

CREATE POLICY "Users can update their own profiles"
  ON profiles
  FOR UPDATE
  USING (auth.uid() = user_id);

CREATE POLICY "Users can delete their own profiles"
  ON profiles
  FOR DELETE
  USING (auth.uid() = user_id);

-- Multi-tenant example
CREATE POLICY "Users can view their own tenant data"
  ON orders
  FOR SELECT
  USING (auth.uid() = user_id AND tenant_id = current_setting('app.current_tenant_id'));

Server-Side Validation

// Secure: server-side auth validation
import { createClient } from '@supabase/supabase-js'
import jwt from 'jsonwebtoken'

const supabaseAdmin = createClient(
  process.env.SUPABASE_URL,
  process.env.SUPABASE_SERVICE_ROLE_KEY // Server-only
)

export async function getUserProfile(userId, token) {
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET)
    if (decoded.uid !== userId) {
      throw new Error('Unauthorized')
    }
    
    const { data, error } = await supabaseAdmin
      .from('profiles')
      .select('*')
      .eq('user_id', userId)
      .single()
    
    return data
  } catch (error) {
    throw new Error('Authentication failed')
  }
}

API Gateway Protection

// Next.js API route with proper auth
import { NextApiRequest, NextApiResponse } from 'next'
import { createClient } from '@supabase/supabase-js'

export default async function handler(
  req: NextApiRequest, 
  res: NextApiResponse
) {
  const supabase = createClient(
    process.env.SUPABASE_URL,
    process.env.SUPABASE_ANON_KEY
  )

  if (!req.headers.authorization) {
    return res.status(401).json({ error: 'Missing token' })
  }

  const token = req.headers.authorization.replace('Bearer ', '')
  const { data: { user } } = await supabase.auth.getUser(token)

  if (!user) {
    return res.status(401).json({ error: 'Invalid token' })
  }

  // Continue with authorized request
}

Service Role Key Management

# Never commit service_role keys echo "SUPABASE_SERVICE_ROLE_KEY=your-key-here" >> .gitignore # Use environment variables in production # Only expose to server-side code # Audit existing keys supabase sql "SELECT * FROM auth.service_roles WHERE created_at > NOW() - INTERVAL '30 days'"

Continuous Monitoring with middleBrick

# Add to CI/CD pipeline
middlebrick scan --spec openapi.json \
  --fail-below B \
  --output json > security-report.json

# GitHub Action integration
- name: middleBrick API Security Scan
  uses: middlebrick/middlebrick-action@v1
  with:
    api-url: ${{ secrets.SUPABASE_URL }}
    fail-threshold: B

Testing Remediation Effectiveness

# Test that auth bypass is fixed
curl -X GET \
  https://your-project.supabase.co/rest/v1/profiles \
  -H "apikey: $(SUPABASE_ANON_KEY)" \
  -H "Content-Type: application/json" \
  | jq '.error' # Should return auth error

Related CWEs: authentication

CWE IDNameSeverity
CWE-287Improper Authentication CRITICAL
CWE-306Missing Authentication for Critical Function CRITICAL
CWE-307Brute Force HIGH
CWE-308Single-Factor Authentication MEDIUM
CWE-309Use of Password System for Primary Authentication MEDIUM
CWE-347Improper Verification of Cryptographic Signature HIGH
CWE-384Session Fixation HIGH
CWE-521Weak Password Requirements MEDIUM
CWE-613Insufficient Session Expiration MEDIUM
CWE-640Weak Password Recovery HIGH

Frequently Asked Questions

How can I tell if my Supabase API has auth bypass vulnerabilities?
Use middleBrick's black-box scanning to test your Supabase endpoints. The scanner specifically checks for missing RLS policies, service role key exposure, and JWT manipulation vulnerabilities. You can also audit your database for tables without RLS policies using SQL queries, and test endpoints by removing authentication headers to see if they return data.
What's the difference between anon key and service_role key in Supabase?
The anon key is for unauthenticated users and respects RLS policies, while the service_role key bypasses all RLS policies and can access any data. Service_role keys should never be exposed to client applications or used in frontend code. middleBrick specifically flags service_role key exposure as a critical auth bypass vulnerability.