AgentStack
SKILL verified MIT Self-run

Supabase Security Audit

skill-hlsitechio-claude-skills-security-supabase-security-audit · by hlsitechio

Audit Supabase project security including Row-Level Security (RLS) policies, SECURITY DEFINER functions, anon/authenticated role grants, service_role key exposure, edge function authentication, and JWT verification on edge endpoints. Use this skill whenever the user mentions Supabase, RLS, row-level security, SECURITY DEFINER, anon role exposure, service_role leak, supabase-js client, edge functi…

No reviews yet
0 installs
0 views
view→install

Install

$ agentstack add skill-hlsitechio-claude-skills-security-supabase-security-audit

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Supabase Security Audit? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Supabase Security Audit

Audit the security posture of a Supabase project across its three exposed surfaces: PostgREST (auto-API over Postgres), Storage, and Edge Functions. Defensive find-and-fix focus.

When this skill applies

  • Reviewing whether RLS is enabled and policies are correct
  • Auditing SECURITY DEFINER functions exposed to anon or authenticated roles
  • Checking grants on anon and authenticated roles
  • Looking for service_role key exposure in client code
  • Reviewing edge function code for missing JWT verification
  • Investigating suspicious activity in a Supabase project (post-incident)

Use other skills for: general app-code review (saas-code-security-review), multi-tenant patterns (saas-tenant-isolation).

Workflow

Follow ../_shared/audit-workflow.md. Skill-specific notes below.

Phase 1: Scope confirmation

Confirm with the user:

  • Project ref (xxxxx.supabase.co)
  • Do you have the service_role key available for read-only audits? (Some checks require it.)
  • Are you the owner/admin of the project?
  • Is this a production project or a staging/dev project?

Never request or store the service_role key in chat. Ask the user to run queries themselves using the SQL editor and paste results.

Phase 2: Inventory

Run the queries in scripts/inventory.sql against the project. They produce:

  • Every table with RLS status
  • Every policy per table
  • Every function with security definer status and grants
  • Every grant on anon and authenticated
  • Every storage bucket and its public/private status
  • Edge function list (via CLI: supabase functions list)

Phase 3: Detection — the checks

RLS coverage — see references/rls-patterns.md
  • SUPA-RLS-1 Every user-data table has RLS enabled (relrowsecurity = true).
  • SUPA-RLS-2 Every user-data table has at least one policy (RLS enabled with no policies = nothing is allowed; usually a config error).
  • SUPA-RLS-3 Policies use auth.uid() / auth.jwt() for identity, not current_user (which is the Postgres role, not the app user).
  • SUPA-RLS-4 Policies cover all four operations (SELECT, INSERT, UPDATE, DELETE) — a permissive SELECT with no UPDATE policy means no UPDATE is allowed (often intended), but the audit should confirm intent.
  • SUPA-RLS-5 Restrictive policies (AS RESTRICTIVE) used where multiple permissive policies could otherwise OR together unsafely.
  • SUPA-RLS-6 USING clauses don't have subqueries that bypass RLS on referenced tables (recursive RLS pitfall).
  • SUPA-RLS-7 Junction/audit/log tables also have RLS — not just the obvious user-facing tables.
Bypass paths — see references/security-definer.md
  • SUPA-SD-1 Every SECURITY DEFINER function inventoried with its grants.
  • SUPA-SD-2 SECURITY DEFINER functions called by anon or authenticated have explicit authorization checks at the top.
  • SUPA-SD-3 search_path set explicitly in every SECURITY DEFINER function (SET search_path = '' or a hardened path), to prevent function-resolution hijacking.
  • SUPA-SD-4 No SECURITY DEFINER function returns data from tables the caller couldn't otherwise reach via RLS, unless that's the explicit intent and authorization is enforced inside.
  • SUPA-SD-5 SECURITY DEFINER functions revoked from public by default; grants only to specific roles.
Role grants — see references/anon-role-exposure.md
  • SUPA-AR-1 anon has SELECT only on tables intended for public access. Any table exposing PII to anon → finding.
  • SUPA-AR-2 anon has no INSERT/UPDATE/DELETE on user-data tables (use functions or authenticated grants).
  • SUPA-AR-3 authenticated grants are minimal — RLS does the policy work, but grants must allow it.
  • SUPA-AR-4 No grants directly to public (covers everyone including future roles).
  • SUPA-AR-5 Sequence usage grants align with table grants (else INSERTs fail oddly or succeed by accident).
Service role exposure
  • SUPA-SR-1 No client code (browser bundle, mobile app, public repo) imports the service_role key. Grep the codebase for the key prefix.
  • SUPA-SR-2 Service role used only in server-side code, edge functions with explicit auth, or admin tooling.
  • SUPA-SR-3 Service role key rotated in last 12 months and after any suspected exposure.
  • SUPA-SR-4 No service_role key in environment variables of client-facing services (Vercel/Netlify "preview" environments that may leak).
Edge functions — see references/edge-functions-auth.md
  • SUPA-EF-1 Every edge function that handles authenticated user data calls supabase.auth.getUser(jwt) to verify and identify the caller.
  • SUPA-EF-2 Functions don't trust client-supplied user IDs; always derive from JWT.
  • SUPA-EF-3 Verify JWT flag enabled in function settings unless explicitly intended to be public (webhook receivers).
  • SUPA-EF-4 Webhook receivers verify signatures (Stripe, Resend, custom) — see saas-api-security/references/webhook-security.md.
  • SUPA-EF-5 Service role key not used inside edge function for queries that should respect RLS — use the user's JWT with the supabase client.
  • SUPA-EF-6 Outbound HTTP requests from edge functions follow SSRF protections (see saas-code-security-review/references/ssrf-patterns.md).
Storage
  • SUPA-ST-1 Buckets marked public only when intent is public; default to private.
  • SUPA-ST-2 Storage policies (RLS-style) defined for private buckets.
  • SUPA-ST-3 Signed URL TTLs reasonable for use case (short for one-time access, longer for embedded content).
  • SUPA-ST-4 No path-traversal-style key construction from user input without sanitization.
Auth configuration
  • SUPA-AUTH-1 Email confirmation required (don't allow unconfirmed accounts to act).
  • SUPA-AUTH-2 Rate limits configured on auth endpoints.
  • SUPA-AUTH-3 Redirect URLs allowlist explicit (no wildcards that could allow OAuth redirect to attacker).
  • SUPA-AUTH-4 Custom SMTP configured for production (Supabase's shared SMTP has reputation limits).
  • SUPA-AUTH-5 MFA enabled on Supabase dashboard for project owners.

Phase 4: Triage

Critical class examples:

  • RLS disabled on any table containing user data
  • service_role key in a public repo or browser bundle
  • SECURITY DEFINER function exposed to anon that returns all rows from a sensitive table
  • Edge function performing privileged operations without JWT verification

Phase 5: Report

Use ../_shared/findings-schema.md. Prefix IDs with SUPA-. Include the table/function name and grant context in evidence.

Scripts

  • scripts/audit_rls.sql — Lists every table with RLS status and policy count
  • scripts/find_definer_funcs.sql — Lists SECURITY DEFINER functions and their grants
  • scripts/anon_grants_report.sql — Lists everything granted to anon and authenticated

Run these in the Supabase SQL editor.

References

  • references/rls-patterns.md — Common RLS policies (good and bad), recursion pitfalls
  • references/security-definer.md — When to use SECURITY DEFINER, how to harden it
  • references/anon-role-exposure.md — What anon should and shouldn't have
  • references/edge-functions-auth.md — JWT verification patterns for Deno edge functions

Assets

  • assets/rls-template.sql — Default-deny policy template for new tables

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.