{"kind":"AgentDefinition","metadata":{"namespace":"community","name":"security-and-owasp","version":"0.1.0"},"spec":{"agents_md":"---\napplyTo: '**'\ndescription: 'Comprehensive secure coding standards based on OWASP Top 10 2025, with 55+ anti-patterns, detection regex, framework-specific fixes for modern web and backend frameworks, and AI/LLM security guidance.'\n---\n\n# Security Standards\n\nComprehensive security rules for web application development. Every anti-pattern includes a severity classification, detection method, OWASP 2025 reference, and corrective code examples.\n\n**Severity levels:**\n\n- **CRITICAL** — Exploitable vulnerability. Must be fixed before merge.\n- **IMPORTANT** — Significant risk. Should be fixed in the same sprint.\n- **SUGGESTION** — Defense-in-depth improvement. Plan for a future iteration.\n\n---\n\n## OWASP Top 10 — 2025 Quick Reference\n\n| # | Category | Key Mitigation |\n|---|----------|----------------|\n| A01 | Broken Access Control | Auth middleware on every endpoint, RBAC, ownership checks |\n| A02 | Security Misconfiguration | Security headers, no debug in prod, no default credentials |\n| A03 | Software Supply Chain Failures *(NEW)* | `npm audit`, lockfile integrity, SBOM, SLSA provenance |\n| A04 | Cryptographic Failures | Argon2id/bcrypt for passwords, TLS everywhere, no secrets in code |\n| A05 | Injection | Parameterized queries, input validation, no raw HTML with user input |\n| A06 | Insecure Design | Threat modeling, secure design patterns, abuse case testing |\n| A07 | Authentication Failures | Rate-limit login, secure session management, MFA |\n| A08 | Software or Data Integrity Failures | SRI for CDN scripts, signed artifacts, no insecure deserialization |\n| A09 | Security Logging and Alerting Failures | Log security events, no PII in logs, correlation IDs, active alerting |\n| A10 | Mishandling of Exceptional Conditions *(NEW)* | Handle all errors, no stack traces in prod, fail-secure |\n\n---\n\n## Injection Anti-Patterns (I1-I8)\n\n### I1: SQL Injection via String Concatenation\n\n- **Severity**: CRITICAL\n- **Detection**: `\\$\\{.*\\}.*(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE)`\n- **OWASP**: A05\n\n```typescript\n// BAD\nconst unsafeResult = await db.query(`SELECT * FROM users WHERE id = ${userId}`);\n\n// GOOD — parameterized query\nconst safeResult = await db.query('SELECT * FROM users WHERE id = $1', [userId]);\n```\n\n### I2: NoSQL Injection (MongoDB Operator Injection)\n\n- **Severity**: CRITICAL\n- **Detection**: `\\{\\s*\\$(?:gt|gte|lt|lte|ne|in|nin|regex|where|exists)`\n- **OWASP**: A05\n\n```typescript\n// BAD — attacker sends { \"password\": { \"$gt\": \"\" } }\nconst user = await User.findOne({ username: req.body.username, password: req.body.password });\n\n// GOOD — validate and cast input types\nconst username = String(req.body.username);\nconst password = String(req.body.password);\nconst user = await User.findOne({ username });\nconst valid = user \u0026\u0026 await verifyPassword(user.passwordHash, password);\n```\n\n### I3: Command Injection (exec with User Input)\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:exec|execSync|execFile|execFileSync)\\s*\\(.*(?:req\\.|params\\.|query\\.|body\\.)`\n- **OWASP**: A05\n\n```typescript\n// BAD — shell interpolation, sync call blocks the event loop\nimport { execFileSync } from 'node:child_process';\nconst unsafeOutput = execFileSync('sh', ['-c', `ls -la ${req.query.dir}`]);\n\n// GOOD — async execFile, arguments array, no shell, bounded time/output\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nconst pExecFile = promisify(execFile);\n\nconst dir = String(req.query.dir ?? '');\nif (!dir || dir.startsWith('-')) throw new Error('Invalid directory');\nconst { stdout: safeOutput } = await pExecFile('ls', ['-la', '--', dir], {\n  timeout: 5_000,      // fail fast on hung processes\n  maxBuffer: 1 \u003c\u003c 20,  // 1 MiB cap to prevent memory exhaustion\n});\n\n// BEST — allowlist validation on top of the async, bounded call above\nconst allowedDirs = ['/data', '/public'];\nif (!allowedDirs.includes(dir)) throw new Error('Invalid directory');\n```\n\nPrefer async `execFile`/`spawn` over `execFileSync` in server handlers: the sync variant blocks Node's event loop and can amplify DoS impact. Always pass a `timeout` and `maxBuffer` to bound execution.\n\n### I4: XSS via Unsanitized HTML Rendering\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:v-html|\\[innerHTML\\]|dangerouslySetInner|bypassSecurityTrust)`\n- **OWASP**: A05\n\nApplies to all frontend frameworks. Each has an API that bypasses default XSS protection:\n\n- **React**: `dangerouslySetInnerHTML` prop with raw user content\n- **Angular**: `[innerHTML]` binding or `bypassSecurityTrustHtml` with unsanitized input\n- **Vue**: `v-html` directive with user-controlled content\n\n```typescript\n// GOOD — sanitize with DOMPurify before rendering any raw HTML\nimport DOMPurify from 'dompurify';\nconst clean = DOMPurify.sanitize(userContent);\n\n// BEST — use text interpolation when HTML is not needed\n// React:   {userContent}\n// Angular: {{ userContent }}\n// Vue:     {{ userContent }}\n```\n\n### I5: SSRF via User-Controlled URLs\n\n- **Severity**: CRITICAL\n- **Detection**: `fetch\\((?:req\\.|params\\.|query\\.|body\\.|url|href)`\n- **OWASP**: A01\n\n```typescript\n// BAD\nconst data = await fetch(req.body.url);\n\n// GOOD — scheme allowlist + hostname allowlist + DNS/IP validation (see TOCTOU note)\nimport { promises as dns } from 'node:dns';\n\nfunction isPrivateIP(ip: string): boolean {\n  // Normalize IPv4-mapped IPv6 (e.g., ::ffff:127.0.0.1 → 127.0.0.1)\n  const normalized = ip.startsWith('::ffff:') ? ip.slice(7) : ip;\n  // IPv4 private/reserved/loopback ranges\n  if (/^(10\\.|172\\.(1[6-9]|2\\d|3[01])\\.|192\\.168\\.|127\\.|0\\.|169\\.254\\.)/.test(normalized)) return true;\n  // IPv6 loopback, link-local (fe80::/10), and unique-local\n  if (/^(::1|fe[89ab]|fc|fd)/i.test(normalized)) return true;\n  return false;\n}\n\nconst parsed = new URL(req.body.url);\nif (parsed.protocol !== 'https:') throw new Error('Only HTTPS allowed');\nconst allowedHosts = ['api.example.com', 'cdn.example.com'];\nif (!allowedHosts.includes(parsed.hostname)) throw new Error('Host not allowed');\n// Resolve all A/AAAA records to prevent DNS rebinding via multiple IPs\nconst resolved = await dns.lookup(parsed.hostname, { all: true });\nif (resolved.length === 0 || resolved.some(({ address }) =\u003e isPrivateIP(address))) {\n  throw new Error('Private or reserved IPs not allowed');\n}\n// Note: for production, pin the resolved IP in the HTTP client to prevent\n// TOCTOU rebinding between this check and fetch(). See undici Agent docs.\nconst data = await fetch(parsed.toString(), { redirect: 'error' });\n```\n\n### I6: Path Traversal in File Operations\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:readFile|readFileSync|createReadStream|path\\.join)\\s*\\(.*(?:req\\.|params\\.|query\\.|body\\.)`\n- **OWASP**: A01\n\n```typescript\n// BAD\nconst file = fs.readFileSync(`/data/${req.params.filename}`);\n\n// GOOD — resolve and validate within allowed directory\nimport path from 'path';\nconst basePath = '/data';\nconst filePath = path.resolve(basePath, req.params.filename);\nif (!filePath.startsWith(basePath + path.sep)) throw new Error('Path traversal detected');\nconst file = fs.readFileSync(filePath);\n```\n\n### I7: Template Injection\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:render|compile|template)\\s*\\(.*(?:req\\.|params\\.|query\\.|body\\.)`\n- **OWASP**: A05\n\n```typescript\n// BAD — user input as template source\nconst html = ejs.render(req.body.template, data);\n\n// GOOD — predefined templates, user input only as data\nconst html = ejs.renderFile('./templates/page.ejs', { content: req.body.content });\n```\n\n### I8: XXE Injection (XML External Entity)\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:parseXml|DOMParser|xml2js|libxmljs).*(?:req\\.|body\\.|file)`\n- **OWASP**: A05\n\n```typescript\n// GOOD — disable external entities in XML parser\nimport { XMLParser } from 'fast-xml-parser';\nconst parser = new XMLParser({\n  allowBooleanAttributes: true,\n  processEntities: false,\n  htmlEntities: false,\n});\nconst result = parser.parse(req.body.xml);\n```\n\n---\n\n## Authentication Anti-Patterns (AU1-AU8)\n\n### AU1: JWT Algorithm Confusion (alg:none)\n\n- **Severity**: CRITICAL\n- **Detection**: `jwt\\.verify\\((?![^)]*\\balgorithms\\b)[^)]*\\)`\n- **OWASP**: A07\n\n```typescript\n// BAD — accepts any algorithm including \"none\"\nconst decoded = jwt.verify(token, secret);\n\n// GOOD — enforce specific algorithm\nconst decoded = jwt.verify(token, publicKey, { algorithms: ['RS256'] });\n```\n\n### AU2: JWT Without Expiration Check\n\n- **Severity**: CRITICAL\n- **Detection**: `jwt\\.sign\\((?![^)]*\\b(?:expiresIn|exp)\\b)[^)]*\\)`\n- **OWASP**: A07\n\n```typescript\n// BAD — token never expires\nconst token = jwt.sign({ userId: user.id }, secret);\n\n// GOOD — short-lived token\nconst token = jwt.sign({ userId: user.id }, secret, { expiresIn: '15m' });\n```\n\n### AU3: JWT Stored in localStorage\n\n- **Severity**: IMPORTANT\n- **Detection**: `localStorage\\.setItem\\(.*(?:token|jwt|auth|session)`\n- **OWASP**: A07\n\n```typescript\n// BAD — accessible via XSS\nlocalStorage.setItem('accessToken', token);\n\n// GOOD — httpOnly cookie set by server\nres.cookie('token', token, { httpOnly: true, secure: true, sameSite: 'strict' });\n```\n\n### AU4: Plaintext / Fast Hash for Passwords (MD5/SHA-1/SHA-256)\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:createHash|md5|sha1|sha256)\\s*\\(.*password`\n- **OWASP**: A04\n\n```typescript\n// BAD — fast hash, no salt\nconst sha256Hash = crypto.createHash('sha256').update(password).digest('hex');\n\n// GOOD — Argon2id (OWASP recommended)\nimport { hash as argon2Hash, argon2id } from 'argon2';\nconst hashed = await argon2Hash(password, { type: argon2id, memoryCost: 65536, timeCost: 3 });\n```\n\n### AU5: Missing Brute-Force Protection on Login\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:post|router\\.post)\\s*\\(\\s*['\"]\\/(?:login|signin|auth|register|reset)`\n- **OWASP**: A07\n\n```typescript\n// BAD — no rate limiting\napp.post('/api/auth/login', loginHandler);\n\n// GOOD\nimport rateLimit from 'express-rate-limit';\nconst authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 5 });\napp.post('/api/auth/login', authLimiter, loginHandler);\n```\n\n### AU6: Missing Session Regeneration on Login (Session Fixation)\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:session|req\\.session)\\s*\\.\\s*(?:userId|user|authenticated)\\s*=`\n- **OWASP**: A07\n\n```typescript\n// GOOD — regenerate session ID on successful login to prevent fixation\nreq.session.regenerate((err) =\u003e {\n  if (err) return next(err);\n  req.session.userId = user.id;\n  req.session.save(next);\n});\n```\n\nRelated: on password change or elevation, also invalidate all other active sessions for the user (e.g., by bumping a `tokenVersion` column and rejecting sessions with a stale version, or by iterating the session store and destroying entries keyed to that user).\n\n### AU7: OAuth Without State Parameter\n\n- **Severity**: CRITICAL\n- **Detection**: `authorize\\?(?![^\\n#]*\\bstate=)[^\\n#]*`\n- **OWASP**: A07\n\n```typescript\n// GOOD — include state parameter for CSRF protection\nconst state = crypto.randomBytes(32).toString('hex');\nsession.oauthState = state;\nconst authUrl = `https://provider.com/authorize?client_id=${clientId}\u0026redirect_uri=${redirectUri}\u0026state=${state}`;\n```\n\n### AU8: Missing PKCE for Public OAuth Clients\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:authorization_code|code).*(?!.*code_challenge)`\n- **OWASP**: A07\n\nUse PKCE (Proof Key for Code Exchange) with S256 challenge method for all public clients (SPAs, mobile).\n\n---\n\n## Authorization Anti-Patterns (AZ1-AZ6)\n\n### AZ1: Missing Auth Middleware on New Endpoints\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:app|router)\\.\\w+\\s*\\(\\s*['\"]\\/api\\/(?:admin|users|settings)`\n- **OWASP**: A01\n\n```typescript\n// BAD\nrouter.delete('/api/users/:id', deleteUser);\n\n// GOOD\nrouter.delete('/api/users/:id', authenticate, authorize('admin'), deleteUser);\n```\n\n### AZ2: Client-Side Only Authorization\n\n- **Severity**: CRITICAL\n- **Detection**: Component guards without server-side checks\n- **OWASP**: A01\n\nFrontend guards are UX only. ALWAYS verify on server.\n\n### AZ3: IDOR (Insecure Direct Object Reference)\n\n- **Severity**: CRITICAL\n- **Detection**: `params\\.(?:id|userId|orderId)` without ownership check\n- **OWASP**: A01\n\n```typescript\n// GOOD — verify ownership\nrouter.get('/api/orders/:orderId', authenticate, async (req, res) =\u003e {\n  const order = await Order.findById(req.params.orderId);\n  if (!order || order.userId !== req.user.id) {\n    return res.status(404).json({ error: 'Not found' });\n  }\n  res.json(order);\n});\n```\n\n### AZ4: Mass Assignment\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:create|update|findOneAndUpdate)\\s*\\(\\s*req\\.body\\s*\\)`\n- **OWASP**: A01\n\n```typescript\n// BAD\nawait User.findByIdAndUpdate(id, req.body);\n\n// GOOD — explicitly pick allowed fields\nconst { name, email, avatar } = req.body;\nawait User.findByIdAndUpdate(id, { name, email, avatar });\n```\n\n### AZ5: Privilege Escalation via Role Parameter\n\n- **Severity**: CRITICAL\n- **Detection**: `req\\.body\\.role|req\\.body\\.isAdmin|req\\.body\\.permissions`\n- **OWASP**: A01\n\n```typescript\n// GOOD — ignore role from input\nconst { name, email, password } = req.body;\nconst user = await User.create({ name, email, password, role: 'user' });\n```\n\n### AZ6: Missing Re-Authentication for Sensitive Operations\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:delete|destroy|remove).*(?:account|user|organization)` without re-auth\n- **OWASP**: A01\n\nRequire current password before account deletion, email change, or other sensitive operations.\n\n---\n\n## Secrets Anti-Patterns (S1-S6)\n\n### S1: Hardcoded API Keys / Tokens\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:password|secret|api_key|token|apiKey)\\s*[:=]\\s*['\"][A-Za-z0-9+/=]{8,}['\"]`\n- **OWASP**: A04\n\n```typescript\n// BAD\nconst API_KEY = 'sk_live_abc123def456';\n\n// GOOD\nconst API_KEY = process.env.API_KEY;\n```\n\n### S2: .env Committed to Git\n\n- **Severity**: CRITICAL\n- **Detection**: `git ls-files .env` (should return empty)\n- **OWASP**: A04\n\n```gitignore\n# .gitignore\n.env\n.env.local\n.env.*.local\n*.pem\n*.key\n```\n\n### S3: Server Secrets Exposed to Client\n\n- **Severity**: CRITICAL\n- **Detection**: `NEXT_PUBLIC_.*(?:SECRET|PRIVATE|PASSWORD|KEY(?!.*PUBLIC))`\n- **OWASP**: A02\n\n```bash\n# BAD\nNEXT_PUBLIC_DATABASE_URL=postgresql://...\n\n# GOOD\nDATABASE_URL=postgresql://...\nNEXT_PUBLIC_API_URL=https://api.example.com\n```\n\nAngular: do not put secrets in `environment.ts` files bundled into the client.\n\n### S4: Default Credentials in Config\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:admin|root|default|test).*(?:password|pass|pwd)\\s*[:=]\\s*['\"](?:admin|root|password|1234|test)`\n- **OWASP**: A02\n\nUse environment variables with validation (zod schema).\n\n### S5: Secrets in CI/CD Pipeline Logs\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:echo|console\\.log|print).*(?:\\$SECRET|\\$TOKEN|\\$PASSWORD|process\\.env)`\n- **OWASP**: A09\n\nUse masked secrets in CI. Never echo environment variables containing secrets.\n\n### S6: Sensitive Data in Error Responses / Stack Traces\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:stack|trace|query|sql).*(?:res\\.json|res\\.send|c\\.JSON)`\n- **OWASP**: A10\n\n```typescript\n// GOOD — generic error to client, details only in logs\napp.use((err, req, res, _next) =\u003e {\n  logger.error({ err, path: req.path, method: req.method });\n  const isDev = process.env.NODE_ENV === 'development';\n  res.status(500).json({\n    error: 'Internal Server Error',\n    ...(isDev \u0026\u0026 { message: err.message }),\n  });\n});\n```\n\n---\n\n## Headers Anti-Patterns (H1-H8)\n\n### H1: Missing Content-Security-Policy\n\n- **Severity**: IMPORTANT\n- **Detection**: Absence of `Content-Security-Policy` header\n- **OWASP**: A02\n\n### H2: CSP with unsafe-inline and unsafe-eval\n\n- **Severity**: IMPORTANT\n- **Detection**: `Content-Security-Policy.*(?:'unsafe-inline'|'unsafe-eval')`\n- **OWASP**: A02\n\nUse nonce-based CSP: `script-src 'self' 'nonce-{SERVER_GENERATED}'`\n\n### H3: Missing Strict-Transport-Security\n\n- **Severity**: IMPORTANT\n- **Detection**: Absence of `Strict-Transport-Security` header\n- **OWASP**: A02\n\nValue: `max-age=31536000; includeSubDomains; preload`\n\n### H4: Missing X-Content-Type-Options\n\n- **Severity**: IMPORTANT\n- **Detection**: Absence of `X-Content-Type-Options: nosniff`\n- **OWASP**: A02\n\n### H5: Missing X-Frame-Options\n\n- **Severity**: IMPORTANT\n- **Detection**: Absence of `X-Frame-Options` header\n- **OWASP**: A02\n\nValue: `DENY`. Also set `Content-Security-Policy: frame-ancestors 'none'`.\n\n### H6: Permissive Referrer-Policy\n\n- **Severity**: SUGGESTION\n- **Detection**: `Referrer-Policy.*(?:unsafe-url|no-referrer-when-downgrade)`\n- **OWASP**: A02\n\nUse: `strict-origin-when-cross-origin`\n\n### H7: Missing Permissions-Policy\n\n- **Severity**: SUGGESTION\n- **Detection**: Absence of `Permissions-Policy` header\n- **OWASP**: A02\n\nValue: `camera=(), microphone=(), geolocation=(), payment=()`\n\n### H8: CORS Wildcard with Credentials\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:cors|Access-Control-Allow-Origin).*\\*`\n- **OWASP**: A02\n\n```typescript\n// GOOD\napp.use(cors({\n  origin: ['https://app.example.com', 'https://staging.example.com'],\n  credentials: true,\n}));\n```\n\n---\n\n## Frontend Anti-Patterns (FE1-FE8)\n\n### FE1: Unsanitized HTML Rendering\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:innerHTML|v-html|dangerouslySetInner)` without DOMPurify\n- **OWASP**: A05\n\nAlways sanitize with DOMPurify before rendering user-controlled HTML. See I4.\n\n### FE2: Dynamic Code Evaluation with User Input\n\n- **Severity**: CRITICAL\n- **Detection**: `eval\\s*\\(`\n- **OWASP**: A05\n\nUse structured data parsers (JSON.parse) instead.\n\n### FE3: postMessage Without Origin Validation\n\n- **Severity**: IMPORTANT\n- **Detection**: `addEventListener\\s*\\(\\s*['\"]message['\"].*(?!.*origin)`\n- **OWASP**: A01\n\n```typescript\nwindow.addEventListener('message', (event) =\u003e {\n  if (event.origin !== 'https://trusted.example.com') return;\n  processData(event.data);\n});\n```\n\n### FE4: Prototype Pollution\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:__proto__|constructor\\.prototype|Object\\.assign)\\s*.*(?:req\\.|body\\.|query\\.)`\n- **OWASP**: A05\n\nValidate and filter keys from user input before merging into objects.\n\n### FE5: Open Redirect\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:window\\.location|location\\.href|router\\.push)\\s*=\\s*(?:req\\.|params\\.|query\\.)`\n- **OWASP**: A01\n\n```typescript\n// GOOD — relative paths only\nconst redirect = new URLSearchParams(window.location.search).get('redirect');\nif (redirect?.startsWith('/') \u0026\u0026 !redirect.startsWith('//')) {\n  window.location.href = redirect;\n}\n```\n\n### FE6: Sensitive Data in localStorage\n\n- **Severity**: IMPORTANT\n- **Detection**: `localStorage\\.setItem\\(.*(?:token|session|credit|ssn|password)`\n- **OWASP**: A07\n\nUse httpOnly cookies for tokens.\n\n### FE7: Missing CSRF Token\n\n- **Severity**: IMPORTANT\n- **Detection**: POST/PUT/DELETE forms without CSRF token or SameSite cookie\n- **OWASP**: A01\n\nUse double-submit cookie or synchronizer token. Next.js Server Actions have built-in CSRF via Origin header.\n\n### FE8: Client-Only Input Validation\n\n- **Severity**: IMPORTANT\n- **Detection**: Form validation only in frontend\n- **OWASP**: A05\n\nALWAYS validate on server too. Use zod, joi, or class-validator.\n\n---\n\n## Dependencies Anti-Patterns (D1-D5)\n\n### D1: Known Vulnerable Dependency\n\n- **Severity**: CRITICAL\n- **Detection**: `npm audit --audit-level=high` exits non-zero\n- **OWASP**: A03\n\n### D2: Lockfile Out of Sync\n\n- **Severity**: IMPORTANT\n- **Detection**: `npm ci` fails\n- **OWASP**: A08\n\n### D3: Typosquatting Risk\n\n- **Severity**: IMPORTANT\n- **Detection**: Manual review of new dependency names\n- **OWASP**: A03\n\n### D4: Postinstall Scripts in New Dependency\n\n- **Severity**: IMPORTANT\n- **Detection**: `\"postinstall\"` in new dependency's package.json\n- **OWASP**: A03\n\n### D5: Unpinned Versions in Production\n\n- **Severity**: SUGGESTION\n- **Detection**: `\":\\s*[\"']\\*[\"']|\":\\s*[\"']latest[\"']`\n- **OWASP**: A03\n\n---\n\n## API Anti-Patterns (AP1-AP6)\n\n### AP1: New Endpoint Without Rate Limiting\n\n- **Severity**: IMPORTANT\n- **OWASP**: A05\n\n### AP2: GraphQL Without Depth Limiting\n\n- **Severity**: IMPORTANT\n- **Detection**: `new ApolloServer` without depth/complexity limits\n- **OWASP**: A05\n\n```typescript\nimport depthLimit from 'graphql-depth-limit';\nconst server = new ApolloServer({\n  schema,\n  validationRules: [depthLimit(5)],\n  introspection: process.env.NODE_ENV !== 'production',\n});\n```\n\n### AP3: File Upload Without Validation\n\n- **Severity**: IMPORTANT\n- **Detection**: `multer|formidable|busboy` without type/size checks\n- **OWASP**: A05\n\n```typescript\nconst upload = multer({\n  dest: 'uploads/',\n  limits: { fileSize: 5 * 1024 * 1024 },\n  fileFilter: (req, file, cb) =\u003e {\n    const allowed = ['image/jpeg', 'image/png', 'image/webp'];\n    cb(null, allowed.includes(file.mimetype));\n  },\n});\n```\n\n### AP4: Webhook Without Signature Verification\n\n- **Severity**: CRITICAL\n- **OWASP**: A08\n\nAlways verify webhook signatures (Stripe, GitHub HMAC, etc.).\n\n### AP5: API Exposing Internal Info\n\n- **Severity**: IMPORTANT\n- **Detection**: `(?:stack|trace|query|sql).*(?:res\\.json|res\\.send)`\n- **OWASP**: A10\n\n### AP6: Missing Request Body Size Limit\n\n- **Severity**: IMPORTANT\n- **Detection**: `express\\.json\\(\\)` without `limit`\n- **OWASP**: A05\n\n```typescript\napp.use(express.json({ limit: '100kb' }));\n```\n\n---\n\n## AI/LLM Security Anti-Patterns (AI1-AI3)\n\n### AI1: Prompt Injection via User Input\n\n- **Severity**: CRITICAL\n- **Detection**: User input concatenated into LLM prompts without sanitization\n- **OWASP**: A05 (Injection)\n\n```typescript\n// BAD — user input directly in prompt\nconst response = await llm.complete(`Summarize this: ${userInput}`);\n\n// GOOD — structured input with system/user message separation\nconst response = await llm.complete({\n  system: \"You are a summarization assistant. Only summarize the provided text.\",\n  user: userInput,\n});\n```\n\n### AI2: LLM Output Used in SQL/Shell Without Sanitization\n\n- **Severity**: CRITICAL\n- **Detection**: LLM response passed to `db.query()`, `exec()`, or template literals without validation\n- **OWASP**: A05 (Injection)\n\nNever trust LLM output as safe. Treat it as untrusted user input — parameterize queries, escape shell arguments, sanitize HTML before rendering.\n\n### AI3: Missing Output Validation from LLM Responses\n\n- **Severity**: IMPORTANT\n- **Detection**: LLM response rendered or executed without schema validation\n- **OWASP**: A08 (Software or Data Integrity Failures)\n\nValidate LLM output against expected schemas (Zod, JSON Schema) before using in application logic. Reject responses that don't match expected structure.\n\n---\n\n## Logging Anti-Patterns (L1-L4)\n\n### L1: Security Events Not Logged\n\n- **Severity**: IMPORTANT\n- **OWASP**: A09\n\nLog: auth failures, access denied, rate limit hits, input validation failures, password changes.\n\n### L2: Sensitive Data in Logs\n\n- **Severity**: CRITICAL\n- **Detection**: `(?:log|logger)\\.\\w+\\(.*(?:password|token|secret|ssn|credit)`\n- **OWASP**: A09\n\n```typescript\nimport pino from 'pino';\nconst logger = pino({ redact: ['req.headers.authorization', 'req.body.password'] });\n```\n\n### L3: Missing Trace IDs\n\n- **Severity**: SUGGESTION\n- **OWASP**: A09\n\n### L4: Log Injection\n\n- **Severity**: IMPORTANT\n- **Detection**: `console\\.log\\(.*\\+.*(?:req\\.|user\\.|body\\.)`\n- **OWASP**: A09\n\nUse structured logging (JSON, auto-escaped) instead of string concatenation.\n\n---\n\n## Framework-Specific: React / Next.js (RX1-RX4)\n\n### RX1: Server Action Without Auth\n\n- **Severity**: CRITICAL\n- **Detection**: `'use server'` function without `auth()` or session check\n- **OWASP**: A01\n\n```typescript\n'use server';\nimport { auth } from '@/auth';\nexport async function deleteUser(id: string) {\n  const session = await auth();\n  if (!session?.user || session.user.role !== 'admin') throw new Error('Unauthorized');\n  await db.user.delete({ where: { id } });\n}\n```\n\n### RX2: process.env Without NEXT_PUBLIC_ in Client\n\n- **Severity**: IMPORTANT\n- **Detection**: `'use client'` file accessing `process.env` without `NEXT_PUBLIC_`\n- **OWASP**: A02\n\n### RX3: RSC Serialization Leaking Data\n\n- **Severity**: IMPORTANT\n- **OWASP**: A01\n\nPick only needed fields before passing DB objects to Client Components.\n\n### RX4: middleware.ts Not Protecting API Routes\n\n- **Severity**: IMPORTANT\n- **Detection**: `config.matcher` not covering `/api/`\n- **OWASP**: A01\n\n---\n\n## Framework-Specific: Angular (NG1-NG3)\n\n### NG1: bypassSecurityTrustHtml with User Input\n\n- **Severity**: CRITICAL\n- **Detection**: `bypassSecurityTrust(?:Html|Script|Style|Url|ResourceUrl)`\n- **OWASP**: A05\n\nSanitize with DOMPurify BEFORE calling bypassSecurityTrust.\n\n### NG2: Template Expression Injection\n\n- **Severity**: IMPORTANT\n- **OWASP**: A05\n\nDo not use JitCompilerFactory with user-controlled templates.\n\n### NG3: HttpInterceptor Not Attaching Auth\n\n- **Severity**: IMPORTANT\n- **OWASP**: A07\n\nUse a centralized `HttpInterceptorFn` for auth tokens.\n\n---\n\n## Framework-Specific: Express (EX1-EX4)\n\n### EX1: Missing helmet.js\n\n- **Severity**: IMPORTANT\n- **OWASP**: A02\n\n```typescript\nimport helmet from 'helmet';\napp.use(helmet());\napp.disable('x-powered-by');\n```\n\n### EX2: express.json() Without Body Size Limit\n\n- **Severity**: IMPORTANT\n- **OWASP**: A05\n\n```typescript\napp.use(express.json({ limit: '100kb' }));\n```\n\n### EX3: Cookie Without Secure Flags\n\n- **Severity**: IMPORTANT\n- **OWASP**: A07\n\n```typescript\nres.cookie('session', value, {\n  httpOnly: true, secure: true, sameSite: 'strict', maxAge: 3600000, path: '/',\n});\n```\n\n### EX4: Error Handler Exposing Stack Trace\n\n- **Severity**: IMPORTANT\n- **OWASP**: A10\n\nOnly expose error details in development mode.\n\n---\n\n## Framework-Specific: Go (GO1-GO3)\n\n### GO1: math/rand for Security Operations\n\n- **Severity**: CRITICAL\n- **Detection**: `math/rand` import in security-related files\n- **OWASP**: A04\n\nUse `crypto/rand` for cryptographically secure random values.\n\n### GO2: TLS InsecureSkipVerify\n\n- **Severity**: CRITICAL\n- **Detection**: `InsecureSkipVerify:\\s*true`\n- **OWASP**: A04\n\nUse system CA pool (default) instead.\n\n### GO3: String Interpolation in SQL\n\n- **Severity**: CRITICAL\n- **Detection**: `fmt\\.Sprintf\\s*\\(.*(?:SELECT|INSERT|UPDATE|DELETE|FROM|WHERE)`\n- **OWASP**: A05\n\n```go\n// GOOD — parameterized\ndb.Where(\"id = ?\", userID).Find(\u0026user)\n```\n\n---\n\n## Security Headers Template\n\n### helmet.js (Express)\n\n```typescript\nimport helmet from 'helmet';\n\napp.use(helmet({\n  contentSecurityPolicy: {\n    directives: {\n      defaultSrc: [\"'self'\"],\n      scriptSrc: [\"'self'\"],\n      styleSrc: [\"'self'\"],\n      imgSrc: [\"'self'\", \"data:\", \"https:\"],\n      fontSrc: [\"'self'\"],\n      connectSrc: [\"'self'\"],\n      frameAncestors: [\"'none'\"],\n      objectSrc: [\"'none'\"],\n      baseUri: [\"'self'\"],\n      formAction: [\"'self'\"],\n      upgradeInsecureRequests: [],\n    },\n  },\n  hsts: { maxAge: 31536000, includeSubDomains: true, preload: true },\n  frameguard: { action: 'deny' },\n  referrerPolicy: { policy: 'strict-origin-when-cross-origin' },\n  crossOriginOpenerPolicy: { policy: 'same-origin' },\n  crossOriginResourcePolicy: { policy: 'same-origin' },\n}));\napp.disable('x-powered-by');\n```\n\n---\n\n## JWT Validation Checklist\n\n1. Verify signature with expected algorithm — reject `alg: none`\n2. Enforce algorithm: `algorithms: ['RS256']` or `['ES256']`\n3. Check `exp` — reject expired tokens\n4. Check `iat` — reject tokens issued too far in the past\n5. Check `aud` — reject tokens not intended for this service\n6. Check `iss` — reject tokens from unknown issuers\n7. Store in httpOnly cookie — not localStorage\n8. Use short-lived access tokens (15 min) + refresh token rotation\n9. Rotate signing keys periodically\n\n---\n\n## Secure Cookie Flags\n\n```\nSet-Cookie: session=value; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600\n```\n\n| Flag | Purpose | When to use |\n|------|---------|-------------|\n| `HttpOnly` | Not accessible via JavaScript (prevents XSS token theft) | Always |\n| `Secure` | Only sent over HTTPS | Always |\n| `SameSite=Strict` | Only sent on same-site requests (strongest CSRF) | Auth/session cookies |\n| `SameSite=Lax` | Sent on top-level navigations (moderate CSRF) | Cookies that need cross-site top-level nav (e.g., OAuth return) |\n| `Path=/` | Limit cookie scope | Always |\n| `Max-Age` | Explicit expiration (prefer over `Expires`) | Always |\n\n---\n\n## Security Checklist\n\n### Authentication and Sessions\n- [ ] Passwords hashed with Argon2id or bcrypt (cost \u003e= 12)\n- [ ] JWT signed with RS256/ES256, algorithm enforced on verify\n- [ ] Access tokens expire in \u003c= 15 minutes\n- [ ] Refresh tokens: one-time use, rotated, stored in httpOnly cookie\n- [ ] Rate limiting on login, registration, and password reset\n- [ ] Session regenerated after authentication\n- [ ] MFA available for privileged accounts\n\n### Authorization\n- [ ] Every API endpoint has auth middleware\n- [ ] Ownership checks on all resource access (prevent IDOR)\n- [ ] Server-side authorization (frontend guards are UX only)\n- [ ] Mass assignment prevented (explicit field selection)\n- [ ] Re-authentication required for sensitive operations\n\n### Input and Output\n- [ ] All user input validated server-side (zod/joi/class-validator)\n- [ ] Parameterized queries for all database operations\n- [ ] HTML output sanitized (DOMPurify) when rendering user content\n- [ ] Error responses do not expose stack traces in production\n\n### Secrets\n- [ ] No hardcoded secrets in source code\n- [ ] `.env` files in `.gitignore`\n- [ ] Server secrets not exposed to client (no NEXT_PUBLIC_ on secrets)\n- [ ] Environment variables validated at startup\n\n### Headers\n- [ ] Content-Security-Policy configured (nonce-based preferred)\n- [ ] Strict-Transport-Security with preload\n- [ ] X-Content-Type-Options: nosniff\n- [ ] X-Frame-Options: DENY\n- [ ] Referrer-Policy: strict-origin-when-cross-origin\n- [ ] Permissions-Policy restricting unused APIs\n- [ ] CORS restricted to known origins\n\n### Dependencies\n- [ ] `npm audit` (or equivalent) passing in CI\n- [ ] Lockfile committed and verified with `npm ci`\n- [ ] New dependencies reviewed for typosquatting and postinstall scripts\n- [ ] No wildcard or \"latest\" versions in production\n\n### Logging\n- [ ] Security events logged (auth failures, access denied, rate limits)\n- [ ] No sensitive data in logs (passwords, tokens, PII)\n- [ ] Structured logging with correlation IDs\n- [ ] Alerts configured for anomalous patterns\n","description":"Comprehensive secure coding standards based on OWASP Top 10 2025, with 55+ anti-patterns, detection regex, framework-specific fixes for modern web and backend frameworks, and AI/LLM security guidance.","import":{"commit_sha":"541b7819d8c3545c6df122491af4fa1eae415779","imported_at":"2026-05-18T20:05:35Z","license_text":"MIT License\n\nCopyright GitHub, Inc.\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","owner":"github","repo":"github/awesome-copilot","source_url":"https://github.com/github/awesome-copilot/blob/541b7819d8c3545c6df122491af4fa1eae415779/instructions/security-and-owasp.instructions.md"},"manifest":{}},"content_hash":[146,114,156,224,84,63,236,77,196,137,216,54,93,20,209,230,155,108,209,248,167,209,182,232,21,128,75,178,57,88,71,162],"trust_level":"unsigned","yanked":false}
