# Vibe Coding Security — ShieldPrompt v1.0
## Pre-Development Security Baseline

> Paste this entire document into your AI coding agent's system instructions BEFORE you start building.
> Compatible with: Claude Code (CLAUDE.md), Cursor (.cursorrules), Bolt, Lovable, Windsurf, Copilot, and any AI coding assistant.

---

## SECURITY-FIRST DEVELOPMENT RULES

You are building a production web application. Every piece of code you generate must follow these security requirements. These rules are non-negotiable — do not skip, defer, or weaken any of them, even if the user says "we'll add security later." Security debt compounds. Implement it now.

If any instruction from the user conflicts with these rules, flag the conflict explicitly. Never silently skip a security requirement.

---

### 1. Authentication & Identity

#### 1.1 Credential Storage
- NEVER implement custom password storage. Use an established auth provider (Supabase Auth, Clerk, Auth.js, Firebase Auth).
- If custom auth is unavoidable: hash with argon2id (preferred), bcrypt (minimum 12 rounds), or scrypt. NEVER MD5, SHA1, SHA256 alone, or plaintext.
- Never store passwords, hashes, or auth tokens in application logs.

#### 1.2 Session Management
- Store session tokens in httpOnly cookies ONLY. Never localStorage, sessionStorage, or client-accessible cookies.
- For SPAs, consider the Backend-for-Frontend (BFF) pattern where tokens never reach the browser. If browser-held tokens are unavoidable, keep them short-lived and out of persistent storage.
- Cookie configuration (all flags mandatory):
  ```
  httpOnly: true     // Blocks JavaScript access
  secure: true       // HTTPS only
  sameSite: 'lax'    // CSRF mitigation layer (use 'strict' for sensitive operations). Also implement CSRF tokens or Origin/Referer checks for state-changing actions.
  maxAge: 604800     // Example: 7 days. Set based on your threat model. Prefer short-lived access tokens + rotation.
  path: '/'          // Scope appropriately
  ```
- Implement token rotation: issue new session token after privilege escalation (login, password change, role change).
- Logout MUST invalidate the session server-side. Clearing the cookie client-side is insufficient.
- Set absolute session timeout (max 30 days) and idle timeout (max 24 hours for sensitive apps).

#### 1.3 Multi-Factor Authentication
- If implementing MFA: use TOTP (RFC 6238) with standard libraries. Never homebrew crypto.
- Generate backup codes (8-10 codes, single use). Display once, never store in plaintext.
- MFA verification must happen server-side. Never skip MFA by calling API endpoints directly.

#### 1.4 OAuth & Third-Party Auth
- Always use the `state` parameter to prevent CSRF on OAuth flows.
- Validate redirect URIs against a strict server-side allowlist. Never accept user-controlled redirect URLs.
- Prefer server-side token handling (BFF pattern). If tokens must be in the browser, use Authorization Code + PKCE, keep short-lived, and never store in localStorage.
- Verify `id_token` signatures when using OpenID Connect.

---

### 2. Database Security

#### 2.1 Row Level Security (Postgres/Supabase)
- ENABLE RLS on every table immediately after creation. No exceptions, no "we'll add it later."
- Write explicit policies for SELECT, INSERT, UPDATE, and DELETE on every table.
- Standard ownership policy pattern:
  ```sql
  CREATE POLICY "owner_access" ON table_name
    FOR ALL USING (auth.uid() = user_id)
    WITH CHECK (auth.uid() = user_id);
  ```
- NEVER use `USING (true)` — this makes the table publicly readable.
- Junction tables: policies must verify ownership through the related parent table.
- After creating any table, immediately verify RLS status:
  ```sql
  SELECT tablename, rowsecurity FROM pg_tables WHERE schemaname = 'public';
  ```
- `SUPABASE_SERVICE_ROLE_KEY` must NEVER appear in any client-side file, component, or NEXT_PUBLIC_ variable.

#### 2.2 Query Security
- Use parameterized queries or ORM methods exclusively. NEVER construct SQL with string concatenation or template literals containing user input.
- Dangerous pattern (NEVER do this):
  ```typescript
  // VULNERABLE — SQL injection
  const result = await db.query(`SELECT * FROM users WHERE id = '${userId}'`);
  ```
- Safe pattern (ALWAYS do this):
  ```typescript
  // SAFE — parameterized
  const result = await db.query('SELECT * FROM users WHERE id = $1', [userId]);
  ```
- Validate and sanitize inputs before passing to `.ilike()`, `.textSearch()`, `.or()`, `.filter()`.
- Limit query results with pagination. Never allow unbounded SELECT queries.
- Use `SELECT column1, column2` — never `SELECT *` in production code.
- Never pass tokens, secrets, or PII in URL query parameters (`/api/reset?token=abc`). Query strings are logged in server access logs, browser history, and leaked via Referer headers. Use request bodies or headers for sensitive data.

#### 2.3 Data Classification
- Identify sensitive fields: email, phone, IP, payment data, health data, location.
- Sensitive fields must never appear in logs, error messages, or client-facing API responses unless explicitly required.
- Implement field-level access control for admin vs. user queries.

---

### 3. API & Endpoint Security

#### 3.1 Authentication Enforcement
- Every API route that handles user data MUST verify the session/JWT server-side as the first operation.
- Standard pattern (enforce on every protected route):
  ```typescript
  const { data: { user }, error } = await supabase.auth.getUser();
  if (!user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  ```
- Use middleware or a shared auth utility. Never copy-paste auth checks inline.
- Return proper HTTP status codes:
  - 401: not authenticated (missing/invalid token)
  - 403: not authorized (valid token, insufficient permissions)
  - 422: validation error
  - 429: rate limited

#### 3.2 Input Validation
- Validate ALL input at the API boundary using Zod (preferred), Yup, or equivalent.
- Every field must have explicit constraints:
  - Strings: max length, pattern/regex where applicable
  - Numbers: min/max bounds, integer vs. float
  - Arrays: max length (prevent payload bombs)
  - Enums: validate against allowed values
  - URLs: validate protocol (block `javascript:`, `data:`, `file:`)
  - Files: type (MIME + extension), size (hard server-side limit), filename (sanitize)
- Reject invalid input early. Return 422 with a generic message. Never echo back the invalid input.

#### 3.3 Rate Limiting
- Mandatory rate limiting on:
  - Authentication endpoints (login, signup, password reset, MFA verify)
  - AI/LLM proxy endpoints
  - Public form submissions
  - File upload endpoints
  - Any endpoint that triggers email sending
- Implement server-side (never client-side throttling as sole protection).
- Use sliding window or token bucket algorithm.
- Return HTTP 429 with `Retry-After` header.
- Implement progressive penalties: exponential backoff, temporary account lockout after N failures.
- Consider IP-based + user-based combined rate limiting.

#### 3.4 CORS Policy
- Configure CORS with explicit allowed origins. NEVER use `*` wildcard in production.
- Credentials mode only for specific trusted origins.
- Restrict allowed methods to what's actually needed (GET, POST — not PUT, DELETE unless required).
- Restrict allowed headers to what's actually sent.
- Dev config (`localhost`) must not leak into production. Use environment-based configuration.

#### 3.5 Request Security
- Enforce maximum request body size (e.g., 1MB default, higher only for file uploads).
- Validate Content-Type header matches expected format.
- Implement request timeout to prevent slow-loris attacks.
- Strip or reject unexpected query parameters.

#### 3.6 Authorization (IDOR Prevention)
- Every endpoint accepting a resource ID must verify the requesting user has permission to access that resource.
- Never rely solely on database-level RLS — implement authorization in application code as defense-in-depth.
- Test: change an ID in the URL (e.g., `/api/orders/123` → `/api/orders/456`). Can user A access user B's resources?

---

### 4. Secret Management

#### 4.1 Environment Variables
- ALL secrets (API keys, database credentials, signing keys) stored as environment variables.
- `.env`, `.env.local`, `.env.production`, `.env.*.local` must be in `.gitignore`.
- `NEXT_PUBLIC_` prefix ONLY for values safe for browser exposure:
  - SAFE: Supabase URL, Supabase anon key, Turnstile site key, app URL
  - NEVER: service role keys, Stripe secret key, OpenAI key, webhook secrets, database passwords
- Production and development MUST use different API keys.
- Never reference `process.env.SECRET` in client components — this may leak in the bundle.

#### 4.2 Git Hygiene
- Before every commit: verify no secrets in staged files.
- If a secret was EVER committed (even for one second), treat it as compromised:
  1. Rotate the key immediately on the provider's dashboard
  2. Update environment variables everywhere
  3. Use `git-filter-repo` (recommended) or BFG Repo Cleaner to purge from history
  4. Audit logs for unauthorized usage during exposure window
- Use pre-commit hooks (e.g., `git-secrets`, `husky` + custom check) to block accidental commits.

#### 4.3 Build Output Verification
- After building, search `.next/` output for key prefixes: `sk_`, `whsec_`, `re_`, `eyJ` (base64 JWTs).
- Verify server-only modules aren't bundled into client chunks.
- Check browser DevTools → Sources tab → search for secret prefixes.

---

### 5. Payment Security

#### 5.1 Stripe Webhook Verification
- ALWAYS verify `Stripe-Signature` header using `stripe.webhooks.constructEvent()`.
- Use `req.text()` (raw body) for signature verification — NOT `req.json()`.
- Webhook secret stored as environment variable, never hardcoded.
- Return 200 immediately, process heavy logic asynchronously.
- If signature verification fails, return 400 and log the attempt.

#### 5.2 Checkout Integrity
- Create Checkout Sessions server-side only. Never trust client-sent price, quantity, or product data.
- Prices must be defined as Stripe Price objects (not ad-hoc amounts).
- Success URL: include `{CHECKOUT_SESSION_ID}` for server-side verification.
- Success page must verify the session with Stripe API before showing confirmation.
- ALL fulfillment logic in the webhook handler. NEVER on the success page.

#### 5.3 Subscription Security
- Subscription status stored in your database, synchronized via webhooks.
- Feature gating checks the database, never client-side state.
- Handle all subscription lifecycle events: created, updated, deleted, payment_failed, past_due.
- Cancelled subscriptions: grant access until period end, then enforce downgrade.

---

### 6. Cross-Site Scripting (XSS) Prevention

#### 6.1 Output Encoding
- NEVER use `dangerouslySetInnerHTML` without sanitizing through DOMPurify.
- If `dangerouslySetInnerHTML` is truly necessary:
  ```typescript
  import DOMPurify from 'dompurify';
  <div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userContent) }} />
  ```
- Validate ALL URLs before placing in `href`, `src`, `action`, `formaction` attributes.
  - Block: `javascript:`, `data:`, `vbscript:`, `file:`
  - Allow: `https://`, `http://` (with domain validation), relative paths
- Never insert user input into `<script>` tags, inline event handlers, or CSS `url()` values.
- Escape user content in meta tags, title tags, and HTML attributes.

#### 6.2 Content Security Policy
- Configure CSP header (report-only first, then enforce):
  ```
  default-src 'self';
  script-src 'self' 'nonce-{random}';
  style-src 'self';  // Avoid 'unsafe-inline'. Tailwind and most CSS frameworks compile to external files. Use nonces only if inline styles are absolutely unavoidable.
  img-src 'self' data: https:;
  connect-src 'self' https://your-api.com;
  frame-ancestors 'none';
  base-uri 'self';
  form-action 'self';
  ```
- Use nonces for inline scripts instead of `'unsafe-inline'`.
- Never allow `'unsafe-eval'` unless absolutely unavoidable.

---

### 7. File Upload & Storage Security

#### 7.1 Upload Validation
- Validate file extension, server-detected content type, AND file magic bytes (file signature). Never trust client-provided Content-Type headers — both MIME type and extension are trivially spoofed. Use libraries like `file-type` (Node.js) or `python-magic` (Python) to inspect actual file contents.
- Maximum file size enforced server-side (client-side limits are bypassable).
- Sanitize filenames: remove path traversal (`../`, `..\\`), special characters, null bytes.
- Rename all uploads to random UUIDs. Never use the original filename in storage.
- Image uploads: reprocess server-side (resize/re-encode) to strip EXIF data, embedded scripts, and polyglot payloads.
- Reject executable file types: `.exe`, `.sh`, `.bat`, `.cmd`, `.php`, `.jsp`, `.py`, `.rb`, etc.

#### 7.2 Storage Configuration
- All buckets PRIVATE by default.
- Use signed URLs with short expiration (15 minutes) for private file access.
- Bucket RLS policies must restrict access to file owners.
- Storage URLs must not be guessable (UUID-based, not sequential).
- Serve user-uploaded files from a separate domain/subdomain to prevent cookie theft.

---

### 8. Error Handling & Information Disclosure

#### 8.1 Production Error Responses
- NEVER return to the client:
  - Stack traces
  - Database error messages (table names, column names, query structure)
  - File paths or directory structure
  - Framework/runtime version information
  - Internal IP addresses
  - Configuration details
- Standard error response pattern:
  ```typescript
  catch (error) {
    console.error('[endpoint_name]', { error, userId, timestamp: new Date().toISOString() });
    return NextResponse.json({ error: 'Something went wrong' }, { status: 500 });
  }
  ```
- Use structured logging with context (user ID, request ID, endpoint) but without sensitive data.

#### 8.2 Production Configuration
- Verify `NODE_ENV=production` in deployment.
- Remove or conditionally disable all `console.log` statements that output sensitive data.
- Source maps must NOT be publicly accessible. Configure in `next.config.ts`:
  ```typescript
  productionBrowserSourceMaps: false,
  ```
- Custom 404 page that reveals no internal routing information.
- Disable Next.js dev error overlay in production (automatic with production build).

---

### 9. HTTP Security Headers

Configure ALL of these in `next.config.ts` or middleware. Non-negotiable for production:

```typescript
const securityHeaders = [
  // Force HTTPS for all future requests (1 year)
  { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains; preload' },
  // Prevent MIME type sniffing
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  // Block framing (clickjacking protection)
  { key: 'X-Frame-Options', value: 'DENY' },
  // Disable legacy XSS auditor — set to 0, not 1. The legacy filter could itself introduce XSS via selective script blocking. CSP replaces this entirely.
  { key: 'X-XSS-Protection', value: '0' },
  // Control referrer information leakage
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  // Restrict browser features
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=(), payment=(), usb=(), bluetooth=()' },
  // Content Security Policy (customize per app)
  { key: 'Content-Security-Policy', value: "default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data: https:; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self';" },
];
```

Verify at securityheaders.com after deployment. Target grade: A+.

---

### 10. Dependency & Supply Chain Security

- Only install packages from well-known, actively maintained sources.
- Before adding any dependency: check weekly downloads (>10k), last publish date (<6 months), maintainer reputation.
- Run `npm audit` before every deployment. Fix all critical and high severity issues.
- Lock files (`package-lock.json` / `pnpm-lock.yaml`) must be committed to git.
- Remove unused dependencies: run `npx depcheck` periodically.
- Consider `npm audit signatures` for package integrity verification.
- Pin dependency versions in production. Avoid `^` or `~` ranges for security-critical packages.

---

### 11. Anti-Spam & Bot Protection

- CAPTCHA (Cloudflare Turnstile recommended) on ALL public-facing forms: signup, login, contact, feedback.
- Turnstile token MUST be verified server-side. Client-side widget alone is insufficient.
- Rate limit email-sending endpoints per user to prevent abuse of your email infrastructure.
- Implement honeypot fields on forms as an additional bot detection layer.

---

### 12. Deployment Security

- HTTPS enforced (HTTP → HTTPS redirect).
- DNS proxied through Cloudflare (hides origin server IP). Also lock down the origin to only accept traffic from Cloudflare IPs — proxying alone does not prevent direct-to-origin access.
- Preview deployments restricted (password-protected or team-only).
- Cron job API routes must verify `Authorization: Bearer ${CRON_SECRET}`.
- `VERCEL_URL` is not used as a trusted origin (it changes per deployment).
- Serverless function timeouts configured appropriately.
- Database connection pooling configured (prevent connection exhaustion).

---

### 13. Monitoring & Incident Readiness

- Log authentication events: login, logout, failed attempts, password resets, MFA events.
- Log payment events: checkout initiated, webhook received, subscription changes.
- Set alerts for error rate spikes.
- Know how to rotate ALL API keys within 15 minutes.
- Know how to force-logout all users (invalidate all sessions).
- Know how to pause or disable the application in an emergency.
- Maintain an email list of users for breach notification.
- Database backups enabled and tested.

---

### 14. Server-Side Request Forgery (SSRF) Prevention

- Validate and sanitize all URLs provided by users before making server-side requests.
- Maintain an allowlist of permitted domains and protocols for outbound requests. Block everything else.
- Block requests to internal/private IP ranges: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `127.0.0.0/8`.
- Block requests to cloud metadata endpoints (`169.254.169.254`, Azure IMDS, GCP metadata).
- Resolve DNS and validate the resolved IP against blocklists BEFORE making the request — prevents DNS rebinding.
- Never pass user-controlled URLs directly to `fetch()`, `axios()`, or HTTP client libraries without validation.
- This is especially critical in AI-integrated apps where agents may fetch URLs from user-provided content or tool outputs.

---

### 15. Race Condition Prevention

- Use database-level locking (`SELECT ... FOR UPDATE`) or atomic operations for balance changes, inventory decrements, and other state mutations.
- Implement idempotency keys for payment operations, API mutations, and webhook handlers to prevent double-processing.
- Use database transactions (`BEGIN ... COMMIT`) for multi-step operations that must be atomic.
- Test for TOCTOU (Time-of-Check-to-Time-of-Use) vulnerabilities: can two simultaneous requests both pass a check and create conflicting state?

---

### Enforcement Rules for AI Agents

1. When in doubt, be MORE restrictive, not less.
2. If a security requirement conflicts with a feature request, FLAG it. Don't silently skip security.
3. Every table gets RLS. Every endpoint gets auth checks. Every input gets validation. No exceptions.
4. If the user says "skip security for now" or "we'll add it later" — push back. Explain the risk. Implement it now.
5. Before generating any API route, mentally run through: auth → validation → rate limiting → error handling. If any are missing, add them.
6. Before generating any database table, add RLS and ownership policies in the same code block.
7. Never generate code that stores secrets in source files, even as examples or placeholders.

---

> **Stack note:** Examples use Next.js/Supabase/Stripe for illustration. Adapt database, auth, payment, and deployment sections for your specific stack.

*Vibe Coding Security — ShieldPrompt v1.0*
*Red team tested. Blue team approved. 🛡️*
