Browse 158 rules, 25 knowledge articles, and 25 prompt templates across security, performance, architecture, and quality.
158 rules
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.
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]
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.
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.
Sequential await calls on independent operations create request waterfalls. Use Promise.all or Suspense boundaries to parallelize.
Unvalidated redirect URLs enable phishing attacks via your domain. Always validate against an allowlist or restrict to relative paths. [CWE-601 · A01:2021]
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.
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 interactive element must be operable via keyboard alone (Tab, Enter, Space, Escape). Users with motor disabilities, RSI, or broken trackpads cannot use a mouse — if your app requires mouse interaction, those users are completely locked out.
CI must run the full test suite and block deployment on failure. Without gate checks, a broken commit reaches production, users experience bugs, and you spend hours debugging under pressure instead of catching it in CI for free.
Fetching related data inside loops creates N+1 queries that scale linearly with data size. Use eager loading or batch queries instead. [CWE-400]
String concatenation in database queries creates injection vulnerabilities. Always use parameterized queries or ORM query builders. [CWE-89 · A03:2021]
Props passed to Client Components are visible in the browser. Never pass API keys, tokens, or full database records to client code. [CWE-200 · A01:2021]
PHP's unserialize() instantiates arbitrary classes and triggers magic methods. Deserialization of user input enables remote code execution via gadget chains. [CWE-502 · A08:2021]
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]
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.
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.
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.
createServiceRoleClient() bypasses ALL RLS policies. Using it in request handlers lets any authenticated user access or modify all data. [CWE-269 · A04:2021]
String interpolation in .rpc() calls or custom PostgreSQL functions allows attackers to inject arbitrary SQL. Always use parameterized queries. [CWE-89 · A03:2021]
App Router route handlers (GET, POST, PUT, DELETE) are public HTTP endpoints. Every exported function must independently verify auth — middleware alone is insufficient. [CWE-862 · A01:2021]
Never commit API keys, passwords, tokens, or credentials to version control. Once a secret is in git history, it is permanently exposed — even deleting the file doesn't remove it from history, and anyone who cloned the repo has a copy forever.
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.
Server Action arguments are deserialized from untrusted HTTP requests. Validate every input with Zod to prevent type confusion and injection attacks. [CWE-20, CWE-502 · A08:2021]
BeforeMerge scans your pull requests against these rules automatically. Get actionable feedback before code ships to production.