Browse 158 rules, 25 knowledge articles, and 25 prompt templates across security, performance, architecture, and quality.
158 rules
Every table must have Row Level Security enabled with at least one policy per operation. Tables without RLS are accessible to any authenticated user. [CWE-862 · A01:2021]
Using NEXT_PUBLIC_ prefix on SUPABASE_SERVICE_ROLE_KEY or DATABASE_URL embeds secrets into client-side JavaScript bundles, bypassing all RLS. [CWE-798 · A07:2021]
Sanitize and escape all user-provided input before rendering in HTML, executing in SQL, or passing to system commands. Unsanitized input is the entry point for XSS, SQL injection, and command injection attacks — the three most exploited vulnerability classes in web applications.
dangerouslySetInnerHTML bypasses React's XSS protection. Always sanitize HTML from external sources with DOMPurify before rendering. [CWE-79 · A03:2021]
Always use parameterized queries or prepared statements, never string concatenation. String-interpolated SQL is the #1 cause of SQL injection — an attacker can modify your query to read, modify, or delete your entire database.
Never use eval(), new Function(), or vm.runInScript() with user-provided input. These functions execute arbitrary code with the full privileges of your Node.js process — an attacker can read files, access databases, or take over the entire server.
WordPress AJAX handlers are public endpoints. wp_ajax_ fires for any logged-in user regardless of role. Always verify nonces and capabilities inside each handler. [CWE-862 · A01:2021]
String interpolation in .rpc() calls or custom PostgreSQL functions allows attackers to inject arbitrary SQL. Always use parameterized queries. [CWE-89 · A03:2021]
Every table in the public schema must have Row Level Security enabled with at least one policy per operation. Without RLS, the Supabase API exposes every row to every request — any browser with your anon key or any logged-in user can read, modify, or delete data belonging to other users. A single table missing RLS can leak your entire user base's private data or let one user overwrite another's records.
Enable all strict flags in tsconfig.json (strict: true). Without strict mode, TypeScript allows null access, implicit any, and unchecked function calls that will crash at runtime.
Always use supabase.auth.getUser() on the server side to verify identity. getSession() reads the JWT from cookies and decodes it without verifying the signature against the auth server — so if an attacker tampers with the token (changing the user ID, role, or email), your server-side code will trust the forged claims as legitimate. This is a complete authentication bypass: the attacker can impersonate any user, escalate privileges, or access data they were never authorized to see.
Next.js middleware can be bypassed (CVE-2025-29927). Always enforce auth checks inside route handlers and Server Actions as defense-in-depth. [CWE-287 · A01:2021]
Every Server Action must verify authentication as its first operation. Server Actions compile to public HTTP POST endpoints — anyone on the internet can call them directly with a simple fetch request, bypassing your UI entirely. Even if you have middleware or layout-level auth checks, the action itself must independently verify the user because external guards can be misconfigured, incomplete, or bypassed. Without per-action auth, an attacker can invoke privileged operations like deleting data, changing settings, or accessing resources they should never reach.
Validate and sanitize all request input (body, query params, headers) before processing. Unvalidated input is the root cause of injection attacks, data corruption, and crashes from malformed data.
createServiceRoleClient() bypasses ALL RLS policies. Using it in request handlers lets any authenticated user access or modify all data. [CWE-269 · A04:2021]
API routes that construct file paths from user input without sanitization allow attackers to read or write arbitrary files using ../ sequences. [CWE-22 · A01:2021]
useEffect hooks that set up subscriptions, timers, or event listeners without cleanup cause memory leaks, stale state updates, and race conditions.
Set security headers on all HTTP responses: Content-Security-Policy, X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security. Missing headers leave your app vulnerable to XSS, clickjacking, MIME sniffing, and protocol downgrade attacks.
Using useEffect + useState for data fetching creates waterfalls, loading spinners, and unnecessary API routes. Use async Server Components instead.
Logging OAuth tokens, API keys, passwords, or PII exposes secrets in log aggregation services and crash reporters. Use scoped loggers with sanitization. [CWE-532 · A09:2021]
Never merge user-controlled objects into application objects using Object.assign, spread, or deep-merge without validation. Prototype pollution lets an attacker inject __proto__ properties that modify the behavior of every object in your application — enabling denial of service, authentication bypass, or remote code execution.
Adding 'use client' to large components or pages ships unnecessary JavaScript to the browser. Push interactivity to the smallest leaf components.
Database access belongs in repository classes, not in services or route handlers. Repositories abstract the data source behind a typed interface. [CWE-1057]
Inserting or updating rows one at a time in a loop creates N HTTP requests. Use .insert([...]) or .upsert([...]) to batch into a single request.
BeforeMerge scans your pull requests against these rules automatically. Get actionable feedback before code ships to production.