Agent Rules for Security and Compliance
AI coding assistants can introduce security vulnerabilities. Not because they're malicious, but because they optimize for working code and working code often takes shortcuts on security. Well-crafted agent rules can systematically prevent the most common security mistakes.
The Security Problem with AI-Generated Code
Studies and real-world experience show that AI-generated code frequently has:
- Missing input validation — the AI assumes input is clean
- Exposed credentials — hardcoded in config files, logs, or error messages
- SQL injection vectors — string interpolation instead of parameterized queries
- Insecure defaults — CORS wildcards, no rate limiting, HTTP instead of HTTPS
- Over-privileged code — requesting more permissions than necessary
- Missing error handling — that leaks stack traces or internal details
Agent rules can prevent all of these at the prompt level.
Core Security Rules Template
markdown## Security Requirements (Non-Negotiable) ### Secrets and Credentials - NEVER hardcode API keys, tokens, passwords, or secrets in code - NEVER include example credentials — even fake-looking ones like `sk_test_abc123` - ALL secrets must come from environment variables - Environment variables: defined in `.env.local` (gitignored) and `.env.example` (committed, no values) ### Input Validation - ALL user input must be validated with Zod before processing - Validate at the boundary (API route, server action, form handler) — not inside services - Always validate: content-type, size limits, data format, and data range ### Database Security - Use Drizzle ORM parameterized queries — NEVER string interpolation in SQL - Never expose raw database errors to API responses — log them, return generic messages - Use transactions for multi-step operations that must be atomic ### API Security - Rate limit all public endpoints using `@upstash/ratelimit` - Authenticate before authorizing — check authentication first, then permissions - Return 404 (not 403) for resources users don't have access to — prevents enumeration - All API error responses: `{ error: { code: string, message: string } }` — no stack traces ### Authentication - Use our `requireAuth()` middleware — never implement auth checks inline - Session tokens: httpOnly, SameSite=Strict, Secure cookies - Never store authentication tokens in localStorage ### XSS Prevention - Never use `dangerouslySetInnerHTML` — sanitize first with DOMPurify if unavoidable - The `Content-Security-Policy` header is already set — don't disable it
OWASP Top 10 — Rule Mapping
| OWASP Category | Specific Agent Rule |
|---|---|
| A01: Broken Access Control | "Always use requireAuth() middleware. Check authorization after authentication. Return 404 for unauthorized resources." |
| A02: Cryptographic Failures | "Never store passwords in plaintext. Use bcrypt with 12+ rounds. Never log PII." |
| A03: Injection | "Use Drizzle ORM parameterized queries. Never interpolate user input into SQL. Use zod for all input." |
| A04: Insecure Design | "Implement rate limiting on all public endpoints. Validate input size and format at API boundaries." |
| A05: Security Misconfiguration | "Never set CORS to *. Never disable CSP. Always run in HTTPS. Never expose stack traces in API responses." |
| A06: Vulnerable Components | "Run pnpm audit after adding dependencies. Pin major versions. Check npm advisories for critical packages." |
| A07: Auth Failures | "Sessions: httpOnly + Secure + SameSite=Strict cookies. Never store auth tokens in localStorage." |
| A08: Data Integrity Failures | "Verify webhook signatures. Validate all data from external APIs with Zod." |
| A09: Logging Failures | "Log all authentication events. Never log PII, passwords, or tokens. Use logger from @/lib/logger." |
| A10: SSRF | "Validate all URLs before fetching. Use an allowlist for external requests. Never fetch user-provided URLs directly." |
Secrets Management Rules
markdown## Secrets Management ### Environment Variable Pattern ```typescript // Correct: validate at app startup via a schema import { z } from 'zod' const envSchema = z.object({ DATABASE_URL: z.string().url(), STRIPE_SECRET_KEY: z.string().startsWith('sk_'), NEXT_PUBLIC_APP_URL: z.string().url(), }) export const env = envSchema.parse(process.env)
If You See Hardcoded Secrets
Replace immediately with the env pattern above and add to .env.local (never commit values).
.env Files
.env.local: real values, gitignored.env.example: template with empty/fake values, committed.env.test: test values for CI, no real credentials
code--- ## Compliance-Specific Rules ### GDPR / Privacy ```markdown ## Privacy and GDPR Rules - Never log email addresses, names, or other PII - User IDs in logs must be hashed: `hashId(userId)` from `@/lib/privacy` - Data deletion: follow the deletion cascade in `db/schema.ts` — all user data must be removable - Don't add new personal data fields to the database without flagging for Privacy review
SOC 2
markdown## Audit Logging (SOC 2 Requirement) - All authentication events: log with `auditLog()` from `@/lib/audit` - All data access on sensitive resources: log with actor, action, resource, timestamp - Admin actions: always audit logged - Audit logs are append-only — never delete or modify them
Security Rules Enforcement in CI
You can make AI security rules machine-enforceable:
yaml# .github/workflows/security.yml - name: Check for hardcoded secrets uses: trufflesecurity/trufflehog@main - name: Dependency audit run: pnpm audit --audit-level=high - name: SAST scan uses: github/codeql-action/analyze@v3
Rule principle: If a security constraint is important enough to put in your agent rules, it should also have a CI check. Rules alone don't guarantee compliance — defense in depth does.