Stop Auth Bypass & RLS Leaks
Before You Deploy
The first static analyzer that correlates your TypeScript AST with your PostgreSQL migrations. Catch getSession spoofing, unprotected storage buckets, and exposed SECURITY DEFINER RPCs offline.
Test Your Code in the Browser
Select a vulnerability preset or edit the code directly to see how Edge Guard correlates TypeScript and PostgreSQL migrations in real-time.
Why Single-Language Tools Fail
Security vulnerabilities in modern web applications live across the boundary between TypeScript server code and PostgreSQL policies.
| Security Vector | ESLint | pgrls / SQL Linters | Supabase Edge Guard |
|---|---|---|---|
| Cross-boundary RPC check (SG004) Client .rpc() calling public SECURITY DEFINER |
Cannot inspect SQL | Cannot inspect TS | Cross-layer audit & safe fix |
| Client bundle secret leakage (SG003) Traces import chains to prevent service_role leaks |
No bundle graph | Cannot inspect TS | BFS import graph reachability |
| Cookie auth spoofing (SG001) Catches getSession() vs getUser() on server |
No boundary model | Cannot inspect TS | Auto-rewrites destructuring |
| Missing table Row Level Security (SG010) Exposed schemas with no RLS protection |
Cannot inspect SQL | Flags SQL only | Flags & generates SQL migration |
| Slow policy initplan (SG005) Unwrapped auth.uid() causing N-query bottlenecks |
Cannot inspect SQL | Static warning | Auto-wraps in (select ...) |
| Lovable / Cursor AI Fix Prompt Ready-to-paste prompts for vibe-coders |
None | None | --format lovable-prompt |
Built-In Heuristic Rules (SG001 - SG018)
Every rule is designed to prefer false negatives over false positives, keeping your CI builds signal-rich and trustworthy.
getSession() reads the cookie without cryptographic verification. Malicious callers can forge JWT claims to authenticate as any user.
A service_role client completely bypasses Row Level Security. Passing user input to it without prior auth verification exposes all data.
A service_role key referenced in a module reachable by the client bundle graph. Anyone can extract the key from browser JS.
Browser calls supabase.rpc() on a SECURITY DEFINER function that is granted to anon/public and never checks auth.uid().
Calling auth.uid() directly forces Postgres to re-evaluate auth for every candidate row. Wrapping in (select auth.uid()) computes it once.
A table created in an exposed schema without ENABLE ROW LEVEL SECURITY allows anyone with the anon key full read and write access.
Zero-Config CI & MCP Integrations
Run on pull requests, pre-commit hooks, or directly inside your AI IDE.
GitHub Action (SARIF + Sticky PR)
Runs on pull requests, uploads SARIF to the Security alerts tab, and keeps a single updated sticky PR comment.
# .github/workflows/edge-guard.yml
name: Security Audit
on: [pull_request]
permissions:
contents: read
security-events: write
pull-requests: write
jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: malikad778/supabase-edge-guard@v0
with:
fail-on: error
upload-sarif: 'true'
comment: 'true'
Cursor & Claude Code (MCP Server)
Run Edge Guard as an interactive tool via Model Context Protocol for automated scanning and fix suggestions.
// cursor.json or claude_desktop_config.json
{
"mcpServers": {
"supabase-edge-guard": {
"command": "npx",
"args": ["-y", "supabase-edge-guard", "mcp"]
}
}
}