What the rls-doctor MCP server does
The rls-doctor MCP server examines PostgreSQL or Supabase databases for configuration patterns that can expose rows or permit unintended writes. It focuses on Row Level Security, including whether RLS is enabled or forced, which policies apply, how roles reach tables, and whether privileges or role attributes bypass policy enforcement.
The audit reports findings with critical, high, medium, low, and informational severities. It can identify unconditional public-style policies, reachable TRUNCATE, application paths to SUPERUSER or BYPASSRLS, broad default privileges, missing effective write checks, permissive policy combinations, and tables that are disabled or inaccessible under RLS. It also reports current access separately from default privileges that affect future tables.
How it works
Static analysis reads database catalog information and applies PostgreSQL command semantics. SELECT and DELETE use USING; INSERT uses WITH CHECK; and UPDATE evaluates both. When an UPDATE or ALL policy omits WITH CHECK, the tool analyzes PostgreSQL’s fallback to the USING expression. Direct, inherited, and SET ROLE membership paths are included, along with PostgreSQL 16 membership options.
Behavioral verification is available through probe. The rls-doctor MCP server can impersonate specified application roles, set request.jwt.claims for supplied Supabase user IDs, and compare rows across owner or tenant columns. The operation runs in a read-only transaction and always rolls back, so it does not mutate the target database.
Setup and configuration
Install with npx rls-doctor, or install the package globally with npm. Node.js 20 or newer is required. Database access can come from DATABASE_URL or SUPABASE_DB_URL; a connection string may also be supplied directly to the command-line interface. Read-only audit credentials are recommended. Passing a secret through a command-line option can expose it in shell history and process listings.
The MCP entry point is started with the mcp command and serves read-only tools over stdio. Audit scope can be limited to one or more schemas, with public as the default. Generic PostgreSQL deployments should specify the application roles whose grants and memberships need to be assessed, rather than relying only on Supabase’s authenticated role.
Tools and capabilities
Available command capabilities include:
- Auditing schemas and producing text, JSON, or SARIF findings.
- Explaining the RLS configuration for an individual table.
- Probing row visibility for application roles and simulated subjects.
- Replaying migrations in disposable PostgreSQL and comparing static results with live behavior.
- Proving isolation claims offline and generating repairs for verification in a shadow database.
- Running a disposable demonstration that shows a cross-tenant leak.
Audit runs can fail on a selected severity, compare against a baseline, emit a score or badge URL, and write a digest-verified coverage receipt. Probe sampling supports configurable owner or tenant columns and row limits.
Limitations and notes
The probe requires application roles and is designed around PostgreSQL access patterns, with Supabase JWT claims used when subjects are supplied. It reports unavailable roles and probe errors separately from confirmed cross-owner or cross-subject reads. A successful static audit does not replace behavioral testing when policies depend on runtime identity or database state.
The tool is read-only for probing, but the broader command set includes repair generation and shadow verification; use the MCP interface when only the read-only capabilities are appropriate. RLS does not protect TRUNCATE, table owners can bypass RLS unless forced, and SUPERUSER or BYPASSRLS paths remain relevant even when FORCE ROW LEVEL SECURITY is enabled.