@baselane/packs 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/aliases.js +1 -0
  2. package/package.json +2 -2
  3. package/packs/database-review/pack.json +75 -9
  4. package/packs/database-review/rendered/.claude/agents/database-reviewer.md +75 -2
  5. package/packs/database-review/rendered/.claude/commands/migration-review.md +6 -0
  6. package/packs/database-review/rendered/.claude/settings.json +11 -0
  7. package/packs/database-review/rendered/.claude/skills/database-migrations/SKILL.md +431 -0
  8. package/packs/database-review/rendered/.claude/skills/mysql-patterns/SKILL.md +414 -0
  9. package/packs/database-review/rendered/.claude/skills/postgres-patterns/SKILL.md +149 -0
  10. package/packs/database-review/rendered/.github/copilot-instructions.md +1096 -14
  11. package/packs/database-review/rendered/AGENTS.md +45 -16
  12. package/packs/database-review/rendered/CLAUDE.md +4 -0
  13. package/packs/database-review/rendered/GEMINI.md +987 -0
  14. package/packs/go-rules/pack.json +65 -9
  15. package/packs/go-rules/rendered/.claude/agents/go-build-resolver.md +90 -0
  16. package/packs/go-rules/rendered/.claude/agents/go-reviewer.md +72 -2
  17. package/packs/go-rules/rendered/.claude/commands/go-build.md +6 -0
  18. package/packs/go-rules/rendered/.claude/commands/go-review.md +1 -1
  19. package/packs/go-rules/rendered/.claude/commands/go-test.md +6 -0
  20. package/packs/go-rules/rendered/.claude/settings.json +9 -0
  21. package/packs/go-rules/rendered/.claude/skills/golang-patterns/SKILL.md +673 -0
  22. package/packs/go-rules/rendered/.claude/skills/golang-testing/SKILL.md +719 -0
  23. package/packs/go-rules/rendered/.github/copilot-instructions.md +1783 -7
  24. package/packs/go-rules/rendered/AGENTS.md +244 -8
  25. package/packs/go-rules/rendered/CLAUDE.md +5 -0
  26. package/packs/go-rules/rendered/GEMINI.md +1394 -0
  27. package/packs/python-rules/pack.json +87 -10
  28. package/packs/python-rules/rendered/.claude/agents/django-reviewer.md +159 -0
  29. package/packs/python-rules/rendered/.claude/agents/fastapi-reviewer.md +70 -0
  30. package/packs/python-rules/rendered/.claude/agents/python-reviewer.md +92 -2
  31. package/packs/python-rules/rendered/.claude/commands/django-review.md +6 -0
  32. package/packs/python-rules/rendered/.claude/commands/fastapi-review.md +6 -0
  33. package/packs/python-rules/rendered/.claude/commands/python-review.md +1 -1
  34. package/packs/python-rules/rendered/.claude/settings.json +1 -1
  35. package/packs/python-rules/rendered/.claude/skills/django-security/SKILL.md +642 -0
  36. package/packs/python-rules/rendered/.claude/skills/django-tdd/SKILL.md +728 -0
  37. package/packs/python-rules/rendered/.claude/skills/fastapi-patterns/SKILL.md +512 -0
  38. package/packs/python-rules/rendered/.claude/skills/python-patterns/SKILL.md +749 -0
  39. package/packs/python-rules/rendered/.claude/skills/python-testing/SKILL.md +815 -0
  40. package/packs/python-rules/rendered/.github/copilot-instructions.md +3815 -12
  41. package/packs/python-rules/rendered/AGENTS.md +73 -13
  42. package/packs/python-rules/rendered/CLAUDE.md +9 -0
  43. package/packs/python-rules/rendered/GEMINI.md +3448 -0
  44. package/packs/security-review/pack.json +51 -7
  45. package/packs/security-review/rendered/.claude/agents/security-reviewer.md +29 -2
  46. package/packs/security-review/rendered/.claude/settings.json +11 -0
  47. package/packs/security-review/rendered/.claude/skills/security-review/SKILL.md +302 -0
  48. package/packs/security-review/rendered/.claude/skills/security-review/cloud-infrastructure-security.md +171 -0
  49. package/packs/security-review/rendered/.claude/skills/security-scan-config/SKILL.md +56 -0
  50. package/packs/security-review/rendered/.github/copilot-instructions.md +658 -15
  51. package/packs/security-review/rendered/AGENTS.md +283 -17
  52. package/packs/security-review/rendered/CLAUDE.md +2 -0
  53. package/packs/security-review/rendered/GEMINI.md +352 -0
  54. package/packs/software-engineer-harness/pack.json +249 -13
  55. package/packs/software-engineer-harness/rendered/.claude/agents/code-explorer.md +67 -0
  56. package/packs/software-engineer-harness/rendered/.claude/agents/performance-optimizer.md +444 -0
  57. package/packs/software-engineer-harness/rendered/.claude/agents/pr-test-analyzer.md +43 -0
  58. package/packs/software-engineer-harness/rendered/.claude/commands/feature-dev.md +6 -0
  59. package/packs/software-engineer-harness/rendered/.claude/settings.json +29 -0
  60. package/packs/software-engineer-harness/rendered/.claude/skills/api-design/SKILL.md +522 -0
  61. package/packs/software-engineer-harness/rendered/.claude/skills/architecture-decision-records/SKILL.md +178 -0
  62. package/packs/software-engineer-harness/rendered/.claude/skills/backend-patterns/SKILL.md +560 -0
  63. package/packs/software-engineer-harness/rendered/.claude/skills/codebase-onboarding/SKILL.md +232 -0
  64. package/packs/software-engineer-harness/rendered/.claude/skills/deployment-patterns/SKILL.md +426 -0
  65. package/packs/software-engineer-harness/rendered/.claude/skills/docker-patterns/SKILL.md +363 -0
  66. package/packs/software-engineer-harness/rendered/.claude/skills/e2e-testing/SKILL.md +325 -0
  67. package/packs/software-engineer-harness/rendered/.claude/skills/tdd-workflow/SKILL.md +580 -0
  68. package/packs/software-engineer-harness/rendered/.github/copilot-instructions.md +3948 -2
  69. package/packs/software-engineer-harness/rendered/AGENTS.md +194 -4
  70. package/packs/software-engineer-harness/rendered/CLAUDE.md +20 -0
  71. package/packs/software-engineer-harness/rendered/GEMINI.md +3208 -0
  72. package/packs/typescript-rules/pack.json +68 -5
  73. package/packs/typescript-rules/rendered/.claude/agents/react-reviewer.md +165 -0
  74. package/packs/typescript-rules/rendered/.claude/agents/type-design-analyzer.md +48 -0
  75. package/packs/typescript-rules/rendered/.claude/commands/react-review.md +6 -0
  76. package/packs/typescript-rules/rendered/.claude/settings.json +9 -0
  77. package/packs/typescript-rules/rendered/.claude/skills/react-patterns/SKILL.md +340 -0
  78. package/packs/typescript-rules/rendered/.claude/skills/react-performance/SKILL.md +573 -0
  79. package/packs/typescript-rules/rendered/.claude/skills/react-testing/SKILL.md +422 -0
  80. package/packs/typescript-rules/rendered/.github/copilot-instructions.md +2459 -53
  81. package/packs/typescript-rules/rendered/AGENTS.md +893 -17
  82. package/packs/typescript-rules/rendered/CLAUDE.md +6 -0
  83. package/packs/typescript-rules/rendered/GEMINI.md +1335 -0
  84. package/packs/ecc-essentials/pack.json +0 -93
  85. package/packs/ecc-essentials/rendered/.claude/settings.json +0 -37
  86. package/packs/ecc-essentials/rendered/.github/copilot-instructions.md +0 -110
  87. package/packs/ecc-essentials/rendered/AGENTS.md +0 -74
  88. package/packs/ecc-essentials/rendered/CLAUDE.md +0 -14
  89. package/packs/ecc-essentials/rendered/GEMINI.md +0 -25
  90. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/build-error-resolver.md +0 -0
  91. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/refactor-cleaner.md +0 -0
  92. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/silent-failure-hunter.md +0 -0
  93. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/agents/tdd-guide.md +0 -0
  94. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/commands/fix-build.md +0 -0
  95. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/commands/hunt-silent-failures.md +0 -0
  96. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/commands/tdd.md +0 -0
  97. /package/packs/{ecc-essentials → software-engineer-harness}/rendered/.claude/skills/tdd-red-green-refactor/SKILL.md +0 -0
@@ -2,9 +2,9 @@
2
2
 
3
3
  ## Security review discipline
4
4
 
5
- Run this against any code that handles user input, authentication, API endpoints, or sensitive data — before it reaches production.
5
+ Run this against any code that handles user input, authentication, API endpoints, secrets, or sensitive data — before it reaches production. This pack merges baselane's own review discipline with the security material from ECC (Everything Claude Code, MIT).
6
6
 
7
- ### Security rules (apply to every endpoint, always)
7
+ ### Core security rules (apply to every endpoint, always)
8
8
 
9
9
  - Never hardcode secrets — read them from environment variables (or a secret manager) and fail fast at startup if a required one is missing.
10
10
  - Use parameterized queries — never build a query by concatenating a user value into a string.
@@ -12,39 +12,330 @@ Run this against any code that handles user input, authentication, API endpoints
12
12
  - Every data query filters by the authenticated user's own id (or explicitly checks an admin role) — never trust a client-supplied id.
13
13
  - Validate all input server-side against a schema — client-side validation alone is not validation.
14
14
  - Return generic error messages to the client; log full detail server-side only.
15
- - Rate-limit authentication endpoints.
15
+ - Rate-limit authentication endpoints and other expensive operations.
16
16
  - Enable row-level security (RLS) by default on any database that supports it.
17
17
  - Set secure cookie flags — `httpOnly`, `secure`, `sameSite` — on every session cookie.
18
+ - Keep dependencies current and act on `npm audit` / `pip-audit` findings.
18
19
 
19
- ### Checklist
20
+ ### Mandatory checks before ANY commit
20
21
 
21
- - **Injection** Validate every external or untrusted input at the boundary before it reaches business logic; fail fast with a clear message. Are queries parameterized? Is user input ever concatenated into a query, shell command, or template string?
22
- - **Authorization** Is every route/mutation checked for auth, not just authentication? Is access scoped to the resource owner, not just "logged in"?
23
- - **Secrets** Never hardcode secrets read them from environment variables and fail fast at startup if a required one is missing. Any hardcoded API key, password, token, or connection string in source?
24
- - **Unsafe deserialization** Is untrusted input ever passed to `eval`, a pickle/deserialize call, or a dynamic `require`/`import` without validation?
25
- - **SSRF** Does the server ever fetch a URL supplied by the user? If so, is the destination allow-listed, not just "looks like a URL"?
26
- - **XSS** Is user content ever rendered as raw HTML (`innerHTML`, `dangerouslySetInnerHTML`) without sanitization?
27
- - **Logging** Do logs ever include a password, token, or full PII record?
22
+ - [ ] No hardcoded secrets (API keys, passwords, tokens, connection strings)
23
+ - [ ] All user inputs validated server-side
24
+ - [ ] SQL injection prevention (parameterized queries only)
25
+ - [ ] XSS prevention (sanitized HTML, CSP configured)
26
+ - [ ] CSRF protection enabled on state-changing routes
27
+ - [ ] Authentication/authorization verified on every route
28
+ - [ ] Rate limiting on all public endpoints
29
+ - [ ] Error messages don't leak sensitive data (stack traces, internals)
28
30
 
29
31
  ### Severity
30
32
 
31
- Hardcoded secrets, injection, and auth bypass are CRITICAL — block merge. XSS and SSRF without an allow-list are HIGH. Missing rate limiting or verbose error messages are MEDIUM.
33
+ Hardcoded secrets, injection, and auth bypass are CRITICAL — block merge. XSS and SSRF without an allow-list, unrestricted shell access on Bash, and BOLA/IDOR gaps are HIGH. Missing rate limiting, verbose error messages, and silent error suppression are MEDIUM. Missing descriptions/hygiene items are INFO.
32
34
 
33
35
  ### False positives to skip
34
36
 
35
- `.env.example` placeholders, clearly-marked test credentials, and public API keys meant to be public are not findings — verify context before flagging.
37
+ `.env.example` placeholders, clearly-marked test credentials, and public API keys meant to be public are not findings — verify context before flagging. SHA-256/MD5 used purely for checksums (not password storage) is not a finding.
38
+
39
+ ## OWASP Top 10 checklist
40
+
41
+ 1. **Injection** — Are queries parameterized? Is user input ever concatenated into a query, shell command, or template string? Are ORMs used safely?
42
+ 2. **Broken authentication** — Are passwords hashed with bcrypt/argon2? Are JWTs validated (signature, expiry, audience)? Are sessions secure?
43
+ 3. **Sensitive data exposure** — Is HTTPS enforced? Are secrets in env vars, never source? Is PII encrypted at rest? Are logs sanitized?
44
+ 4. **XXE** — Are XML parsers configured to disable external entities?
45
+ 5. **Broken access control** — Is auth checked on every route/mutation, not just authentication? Is CORS configured correctly (no wildcard with credentials)?
46
+ 6. **Security misconfiguration** — Are default credentials changed? Is debug mode off in prod? Are security headers set?
47
+ 7. **XSS** — Is output escaped? Is CSP set? Is the framework's auto-escaping relied on rather than bypassed?
48
+ 8. **Insecure deserialization** — Is untrusted input ever passed to `eval`, a pickle/deserialize call, or a dynamic `require`/`import` without validation?
49
+ 9. **Using components with known vulnerabilities** — Are dependencies current? Is `npm audit` / `pip-audit` clean?
50
+ 10. **Insufficient logging & monitoring** — Are security events (auth failures, admin actions) logged? Are alerts configured for anomalies?
51
+
52
+ Also check, beyond the classic 10:
53
+
54
+ - **SSRF** — Does the server ever fetch a URL supplied by the user? If so, is the destination allow-listed, not just "looks like a URL"?
55
+ - **Logging hygiene** — Do logs ever include a password, token, session id, or full PII record?
56
+
57
+ ### Code pattern reference
58
+
59
+ | Pattern | Severity | Fix |
60
+ | --- | --- | --- |
61
+ | Hardcoded secrets | CRITICAL | Read from `process.env` / secret manager |
62
+ | Shell command built from user input | CRITICAL | Use safe APIs or `execFile` with an argument array |
63
+ | String-concatenated SQL | CRITICAL | Parameterized queries |
64
+ | `innerHTML` / `dangerouslySetInnerHTML` on user content | HIGH | Sanitize (e.g. DOMPurify) or use `textContent` |
65
+ | `fetch(userProvidedUrl)` with no allow-list | HIGH | Allow-list destination hosts |
66
+ | Plaintext password comparison | CRITICAL | `bcrypt.compare()` / `argon2.verify()` |
67
+ | No auth check on a route | CRITICAL | Add authentication + authorization middleware |
68
+ | Balance/quantity check without a lock | CRITICAL | Use `FOR UPDATE` / an explicit transaction |
69
+ | No rate limiting on an expensive or auth route | HIGH | Add rate limiting middleware |
70
+ | Logging passwords/secrets/tokens | MEDIUM | Redact before logging |
71
+
72
+ ## Secrets management
73
+
74
+ ```typescript
75
+ // FAIL — hardcoded
76
+ const apiKey = "sk-proj-xxxxx";
77
+
78
+ // PASS — env var, fail fast if missing
79
+ const apiKey = process.env.OPENAI_API_KEY;
80
+ if (!apiKey) throw new Error("OPENAI_API_KEY not configured");
81
+ ```
82
+
83
+ - [ ] No hardcoded API keys, tokens, or passwords
84
+ - [ ] All secrets in environment variables or a secrets manager
85
+ - [ ] `.env.local` (and equivalents) in `.gitignore`
86
+ - [ ] No secrets in git history
87
+ - [ ] Production secrets live in the hosting platform's secret store, not in a committed file
88
+
89
+ In cloud environments, prefer a managed secrets manager over a bare environment variable so access is audited and rotation is automatic:
90
+
91
+ ```typescript
92
+ // PASS — cloud secrets manager, audited + rotatable
93
+ import { SecretsManager } from "@aws-sdk/client-secrets-manager";
94
+ const client = new SecretsManager({ region: "us-east-1" });
95
+ const secret = await client.getSecretValue({ SecretId: "prod/api-key" });
96
+ ```
97
+
98
+ ## Input validation
99
+
100
+ ```typescript
101
+ import { z } from "zod";
102
+
103
+ const CreateUserSchema = z.object({
104
+ email: z.string().email(),
105
+ name: z.string().min(1).max(100),
106
+ age: z.number().int().min(0).max(150),
107
+ });
108
+
109
+ export async function createUser(input: unknown) {
110
+ const validated = CreateUserSchema.parse(input); // throws on bad shape
111
+ return await db.users.create(validated);
112
+ }
113
+ ```
114
+
115
+ File uploads: enforce a size limit, an allow-listed MIME type, and a matching extension — all three, not just one.
116
+
117
+ - [ ] All user inputs validated server-side with a schema
118
+ - [ ] File uploads restricted (size, type, extension)
119
+ - [ ] No direct use of user input in a query, shell command, or template string
120
+ - [ ] Whitelist validation, not blacklist
121
+ - [ ] Error messages don't leak internal detail
122
+
123
+ ## SQL injection prevention
124
+
125
+ ```typescript
126
+ // FAIL — string-concatenated SQL
127
+ const query = `SELECT * FROM users WHERE email = '${userEmail}'`;
128
+
129
+ // PASS — parameterized
130
+ await db.query("SELECT * FROM users WHERE email = $1", [userEmail]);
131
+ ```
132
+
133
+ - [ ] All database queries use parameterized queries or a query builder
134
+ - [ ] No string concatenation in SQL
135
+ - [ ] ORM/query builder used correctly (no raw-string escape hatches with user input)
136
+
137
+ ## Authentication & authorization
138
+
139
+ ```typescript
140
+ // FAIL — token in localStorage (readable by any XSS)
141
+ localStorage.setItem("token", token);
142
+
143
+ // PASS — httpOnly cookie
144
+ res.setHeader("Set-Cookie", `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`);
145
+ ```
146
+
147
+ ```typescript
148
+ export async function deleteUser(userId: string, requesterId: string) {
149
+ const requester = await db.users.findUnique({ where: { id: requesterId } });
150
+ if (requester.role !== "admin") {
151
+ return NextResponse.json({ error: "Unauthorized" }, { status: 403 });
152
+ }
153
+ await db.users.delete({ where: { id: userId } });
154
+ }
155
+ ```
156
+
157
+ Row-level security, once available, is the backstop that catches an authorization check a developer forgot to write:
158
+
159
+ ```sql
160
+ ALTER TABLE users ENABLE ROW LEVEL SECURITY;
161
+ CREATE POLICY "Users view own data" ON users FOR SELECT USING (auth.uid() = id);
162
+ CREATE POLICY "Users update own data" ON users FOR UPDATE USING (auth.uid() = id);
163
+ ```
164
+
165
+ - [ ] Tokens stored in httpOnly cookies, not `localStorage`
166
+ - [ ] Authorization checked before every sensitive operation, scoped to resource owner (the BOLA/IDOR check — `GET /api/invoices/43` must 403/404 for anyone but the invoice's owner or an explicit admin)
167
+ - [ ] Row-level security enabled where the database supports it
168
+ - [ ] Session management is secure (rotation on privilege change, expiry enforced)
169
+
170
+ ## XSS prevention & CSP
171
+
172
+ ```typescript
173
+ import DOMPurify from "isomorphic-dompurify";
174
+
175
+ function renderUserContent(html: string) {
176
+ const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ["b", "i", "em", "strong", "p"], ALLOWED_ATTR: [] });
177
+ return <div dangerouslySetInnerHTML={{ __html: clean }} />;
178
+ }
179
+ ```
180
+
181
+ Start CSP strict and loosen only with a documented removal plan. Do not default to `'unsafe-inline'` or `'unsafe-eval'` — they neutralize much of CSP's protection and should be treated as temporary compatibility debt.
182
+
183
+ ```
184
+ Content-Security-Policy:
185
+ default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none';
186
+ script-src 'self'; style-src 'self'; img-src 'self' data: https:; font-src 'self';
187
+ ```
188
+
189
+ - [ ] User-provided HTML sanitized before render
190
+ - [ ] CSP headers configured (no blanket `unsafe-inline`/`unsafe-eval`)
191
+ - [ ] No unvalidated dynamic content rendering
192
+ - [ ] Framework's built-in escaping relied on rather than bypassed
193
+
194
+ ## CSRF
195
+
196
+ ```typescript
197
+ export async function POST(request: Request) {
198
+ const token = request.headers.get("X-CSRF-Token");
199
+ if (!csrf.verify(token)) return NextResponse.json({ error: "Invalid CSRF token" }, { status: 403 });
200
+ }
201
+ ```
202
+
203
+ - [ ] CSRF tokens on state-changing operations
204
+ - [ ] `SameSite=Strict` on session cookies
205
+ - [ ] Double-submit cookie pattern where token-based CSRF isn't practical
206
+
207
+ ## Rate limiting
208
+
209
+ ```typescript
210
+ const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100 });
211
+ app.use("/api/", limiter);
212
+
213
+ const searchLimiter = rateLimit({ windowMs: 60 * 1000, max: 10 }); // stricter for expensive ops
214
+ app.use("/api/search", searchLimiter);
215
+ ```
216
+
217
+ - [ ] Rate limiting on all public API endpoints
218
+ - [ ] Stricter limits on expensive operations (search, auth, sends)
219
+ - [ ] Limits keyed by IP and, where authenticated, by user
220
+
221
+ ## Sensitive data exposure & logging
222
+
223
+ ```typescript
224
+ // FAIL
225
+ console.log("User login:", { email, password });
226
+ catch (error) { return NextResponse.json({ error: error.message, stack: error.stack }, { status: 500 }); }
227
+
228
+ // PASS
229
+ console.log("User login:", { email, userId });
230
+ catch (error) {
231
+ console.error("Internal error:", error); // full detail server-side only
232
+ return NextResponse.json({ error: "An error occurred. Please try again." }, { status: 500 });
233
+ }
234
+ ```
235
+
236
+ - [ ] No passwords, tokens, secrets, or full PII in logs
237
+ - [ ] Error messages generic for the client; detail logged server-side only
238
+ - [ ] No stack traces exposed to users
239
+
240
+ ## Dependency security
241
+
242
+ ```bash
243
+ npm audit --audit-level=high
244
+ npm audit fix
245
+ npm outdated
246
+ npm ci # reproducible installs in CI, not `npm install`
247
+ ```
248
+
249
+ - [ ] Dependencies current, `npm audit` clean at the chosen severity threshold
250
+ - [ ] Lock files committed
251
+ - [ ] Automated dependency update tooling enabled (e.g. Dependabot) where the platform supports it
252
+
253
+ ## Cloud & infrastructure security (summary)
254
+
255
+ Full detail lives in the `cloud-infrastructure-security` reference alongside the `security-review` skill. Highlights to check on any deploy-touching change:
256
+
257
+ - **IAM** — least privilege (no `*` actions on `*` resources), MFA on privileged accounts, service accounts use roles rather than long-lived keys.
258
+ - **Network** — databases not publicly accessible, security groups scoped by CIDR and port, no `0.0.0.0/0` on anything but public HTTP(S).
259
+ - **Secrets** — cloud secrets manager with rotation, not a bare env var for long-lived production credentials.
260
+ - **CI/CD** — OIDC instead of long-lived cloud credentials, secret scanning and dependency audit as pipeline steps, branch protection + required review before merge.
261
+ - **CDN/WAF** — security headers set (`X-Frame-Options`, `X-Content-Type-Options`, `Referrer-Policy`), WAF/rate limiting enabled at the edge where available.
262
+ - **Backups** — automated, retention meets the project's compliance bar, recovery tested rather than assumed.
263
+
264
+ ## Agent & harness security minimum bar
265
+
266
+ This project's own reviewer and the code it reviews increasingly run inside an AI coding harness, which is itself part of the attack surface (poisoned repo config, malicious hook definitions, prompt injection via fetched content or untrusted files). Treat these as review targets too, not just application code:
267
+
268
+ - Agent/bot identities are separate from personal accounts (a dedicated bot user/email/token), never the developer's own credentials.
269
+ - Credentials handed to an agent are short-lived and scoped to what the task needs — not org-wide, not long-lived.
270
+ - Untrusted or foreign-content-heavy work (unfamiliar repos, email/PDF/webpage ingestion) runs in an isolated sandbox with no default network egress, not on the primary machine.
271
+ - Harness permission config denies reads/writes to secret-bearing paths (`~/.ssh`, `~/.aws`, `.env*`) by default; a workflow that only needs to read a repo and run tests should not be able to read the home directory.
272
+ - Anything read from outside the repo (fetched pages, tool output, PR/issue bodies, file attachments) is treated as untrusted content, not as instructions — a boundary a reviewer should flag if code blurs it (e.g. an agent tool that executes text from a fetched document).
273
+ - The agent is not the final authority for unsandboxed shell execution, network egress, secret reads, or writes outside the workspace — a human-in-the-loop approval sits between the model and the action for all four.
274
+ - Tool calls, approval decisions, files touched, and network attempts are logged somewhere a human can review after the fact.
275
+ - Long-running/autonomous agent processes have an actual stop path (process-group kill, not just the parent process) and a heartbeat-based dead-man switch rather than relying on the process stopping itself.
276
+ - Persistent agent memory stays narrow: no secrets in memory files, and memory from an untrusted run is reset or rotated rather than carried forward indefinitely.
277
+ - Skills, hooks, MCP server configs, and agent descriptors pulled from outside the team are reviewed like any other supply-chain artifact before being trusted (unicode/zero-width-character checks, no unexplained outbound network commands, no silent permission escalation).
278
+
279
+ ## Pre-deployment security checklist
280
+
281
+ Before ANY production deployment:
282
+
283
+ - [ ] Secrets: no hardcoded secrets, all in env vars or a secrets manager
284
+ - [ ] Input validation: all user inputs validated server-side
285
+ - [ ] SQL injection: all queries parameterized
286
+ - [ ] XSS: user content sanitized, CSP configured
287
+ - [ ] CSRF: protection enabled on state-changing routes
288
+ - [ ] Authentication: proper token handling (httpOnly cookies)
289
+ - [ ] Authorization: role/ownership checks in place on every route
290
+ - [ ] Rate limiting: enabled on public and expensive endpoints
291
+ - [ ] HTTPS enforced in production
292
+ - [ ] Security headers configured (CSP, X-Frame-Options, etc.)
293
+ - [ ] Error handling: no sensitive data in client-facing errors
294
+ - [ ] Logging: no sensitive data logged
295
+ - [ ] Dependencies: up to date, no known-high/critical vulnerabilities
296
+ - [ ] Row-level security enabled where the database supports it
297
+ - [ ] CORS properly scoped (no wildcard origin with credentials)
298
+ - [ ] File uploads validated (size, type, extension)
36
299
 
37
300
  ## Workflow pack: Security review
38
301
 
39
- A 4-layer pre-deploy security audit (secrets, authentication, input validation, data access) with per-layer prompts and a scan toolkit, a reviewer role, a /security-scan diff check, a /security-audit pre-deploy pass, a pre-ship Stop-hook reminder, and baseline security rules for every endpoint — flags real vulnerabilities with severity and file:line, not theater.
302
+ Comprehensive OWASP Top 10 + secrets/input/auth/XSS/CSRF/rate-limiting/logging/dependency/cloud-infra security review discipline, a 4-layer pre-deploy audit, a full-checklist skill with cloud-infra reference, an AI-harness config scan skill, a reviewer agent, full-audit and diff-scoped scan commands, and a portable secret-leak guard hook — flags real vulnerabilities with severity and file:line, not theater.
303
+
304
+ When acting as the security-reviewer role: You are an expert security reviewer focused on identifying and remediating real vulnerabilities before they reach production. Read the changed code and check it against the security-review checklist in this pack's context: injection, broken authentication, sensitive data exposure, broken access control, security misconfiguration, XSS, insecure deserialization, known-vulnerable dependencies, insufficient logging, SSRF, and hardcoded secrets.
305
+
306
+ ## Review workflow
307
+
308
+ 1. **Initial scan** — search the diff (and, if relevant, git history) for hardcoded secrets; identify high-risk areas touched: auth, API endpoints, DB queries, file uploads, payments, webhooks, MCP/agent configuration.
309
+ 2. **OWASP Top 10 pass** — work through each of the 10 categories in this pack's context against the actual code, not in the abstract.
310
+ 3. **Pattern match** — flag any of this pack's known-bad patterns on sight (hardcoded secret, shell command built from user input, string-concatenated SQL, unsanitized `innerHTML`, unallow-listed `fetch(userUrl)`, plaintext password comparison, missing auth check, unlocked balance/quantity check, missing rate limiting, secrets in logs).
311
+
312
+ ## Reporting
313
+
314
+ For each finding, cite the exact file:line, name the concrete input and outcome that makes it exploitable, and give a severity:
315
+
316
+ - **CRITICAL** — hardcoded secrets, injection, auth bypass. Blocks merge.
317
+ - **HIGH** — XSS/SSRF without an allow-list, a BOLA/IDOR gap, unrestricted shell access.
318
+ - **MEDIUM** — missing rate limiting, verbose error messages, silent error suppression.
319
+ - **INFO** — hygiene items (missing descriptions, outdated-but-non-vulnerable dependency).
40
320
 
41
- When acting as the security-reviewer role: You are a security reviewer. Read the changed code and check it against the security-review checklist in context: injection, authorization, hardcoded secrets, unsafe deserialization, SSRF, XSS, and sensitive-data logging. For each finding, cite the exact file:line, name the concrete input and outcome that makes it exploitable, and give severity (CRITICAL/HIGH/MEDIUM). Skip findings you cannot point to in the code do not manufacture issues to look thorough. If nothing is exploitable, say so and approve.
321
+ For every finding, give a concrete fix a corrected code snippet, not just a description of the problem. Skip findings you cannot point to in the code; do not manufacture issues to look thorough. Common false positives to verify context on before flagging: `.env.example` placeholders, clearly-marked test credentials, intentionally-public API keys, and SHA-256/MD5 used for checksums rather than password storage.
322
+
323
+ ## When to run
324
+
325
+ Always after: new API endpoints, auth code changes, user input handling, DB query changes, file uploads, payment code, external API integrations, dependency updates, or changes to this project's own AI-harness configuration (hooks, MCP servers, agent/skill definitions). Immediately for: production incidents, dependency CVEs, user security reports, or before any major release.
326
+
327
+ ## Reference
328
+
329
+ For the full worked checklist with code examples, see the `security-review` skill in this pack (and its `cloud-infrastructure-security` reference for deploy-touching changes). For the 4-layer pre-deploy pass, see the `security-audit` skill.
330
+
331
+ **Remember**: be thorough and specific, not performative. One real, well-cited finding is worth more than ten vague ones.
42
332
 
43
333
  Workflow steps:
44
334
 
45
335
  - security-scan: Invoke the security-reviewer subagent over the current diff (or $ARGUMENTS if given). Report findings grouped by severity (CRITICAL, HIGH, MEDIUM) with file:line and fix for each. End with a verdict: approve, or block until CRITICAL/HIGH issues are fixed.
46
336
  - security-audit: Run the security-audit skill's 4-layer pass over the current diff (or $ARGUMENTS if given): secrets, authentication, input validation, data access. For each layer, run the relevant toolkit command when it's installed (gitleaks, trufflehog, npm audit / pip-audit, semgrep --config auto) and answer that layer's audit prompt against the actual code. Report findings grouped by layer with file:line and severity (CRITICAL/HIGH/MEDIUM). End with a verdict: safe to ship, or block until CRITICAL/HIGH issues are fixed.
47
337
 
338
+ - Security check: never paste or echo a live secret (API key, token, cookie, password, .pem contents) into this command's output or a log — reference an environment variable or secret manager instead.
48
339
  - Security check: any user input, external fetch, or deserialized data crossing a trust boundary here? Validate it before it's used.
49
340
  - After an edit, scan the working tree for committed secrets with gitleaks when it is installed.
50
341
  - Before ending the session, run the pre-deploy security toolkit and remind to run /security-audit before shipping.
@@ -135,3 +426,355 @@ the failure where the bad data actually entered, where the error message can sti
135
426
  HTTP request bodies and query params · file and config contents · third-party API responses ·
136
427
  environment variables (validate presence and format at startup) · deserialized messages/events ·
137
428
  anything read from a store you did not just write in the same transaction.
429
+
430
+ ### security-review
431
+
432
+ Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features. Full worked checklist with code examples for every OWASP Top 10 category, plus a cloud-infrastructure reference.
433
+
434
+ # Security review
435
+
436
+ Comprehensive security review discipline for code that adds authentication, handles user input, works with secrets, exposes an API endpoint, or touches payment/sensitive data. This is the full checklist version of the pack's own context — use it when you need the worked examples inline rather than the summary.
437
+
438
+ ## When to activate
439
+
440
+ - Implementing authentication or authorization
441
+ - Handling user input or file uploads
442
+ - Creating new API endpoints
443
+ - Working with secrets or credentials
444
+ - Implementing payment features
445
+ - Storing or transmitting sensitive data
446
+ - Integrating third-party APIs
447
+
448
+ ## Secrets management
449
+
450
+ FAIL:
451
+ ```typescript
452
+ const apiKey = "sk-proj-xxxxx" // hardcoded secret
453
+ const dbPassword = "password123" // in source code
454
+ ```
455
+
456
+ PASS:
457
+ ```typescript
458
+ const apiKey = process.env.OPENAI_API_KEY
459
+ if (!apiKey) throw new Error('OPENAI_API_KEY not configured')
460
+ ```
461
+
462
+ Verify: no hardcoded API keys/tokens/passwords · all secrets in env vars · `.env.local` gitignored · no secrets in git history · production secrets in the hosting platform's secret store.
463
+
464
+ ## Input validation
465
+
466
+ ```typescript
467
+ import { z } from 'zod'
468
+
469
+ const CreateUserSchema = z.object({
470
+ email: z.string().email(),
471
+ name: z.string().min(1).max(100),
472
+ age: z.number().int().min(0).max(150)
473
+ })
474
+
475
+ export async function createUser(input: unknown) {
476
+ try {
477
+ const validated = CreateUserSchema.parse(input)
478
+ return await db.users.create(validated)
479
+ } catch (error) {
480
+ if (error instanceof z.ZodError) return { success: false, errors: error.issues }
481
+ throw error
482
+ }
483
+ }
484
+ ```
485
+
486
+ File upload validation checks size, MIME type, AND extension — never just one:
487
+
488
+ ```typescript
489
+ function validateFileUpload(file: File) {
490
+ const maxSize = 5 * 1024 * 1024
491
+ if (file.size > maxSize) throw new Error('File too large (max 5MB)')
492
+
493
+ const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
494
+ if (!allowedTypes.includes(file.type)) throw new Error('Invalid file type')
495
+
496
+ const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']
497
+ const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
498
+ if (!extension || !allowedExtensions.includes(extension)) throw new Error('Invalid file extension')
499
+
500
+ return true
501
+ }
502
+ ```
503
+
504
+ Verify: all user inputs validated with schemas · file uploads restricted (size, type, extension) · no direct use of user input in queries · whitelist validation (not blacklist) · error messages don't leak sensitive info.
505
+
506
+ ## SQL injection prevention
507
+
508
+ FAIL:
509
+ ```typescript
510
+ const query = `SELECT * FROM users WHERE email = '${userEmail}'`
511
+ await db.query(query)
512
+ ```
513
+
514
+ PASS:
515
+ ```typescript
516
+ const { data } = await supabase.from('users').select('*').eq('email', userEmail)
517
+ // or
518
+ await db.query('SELECT * FROM users WHERE email = $1', [userEmail])
519
+ ```
520
+
521
+ Verify: all database queries use parameterized queries · no string concatenation in SQL · ORM/query builder used correctly.
522
+
523
+ ## Authentication & authorization
524
+
525
+ ```typescript
526
+ // FAIL: localStorage is vulnerable to XSS
527
+ localStorage.setItem('token', token)
528
+
529
+ // PASS: httpOnly cookie
530
+ res.setHeader('Set-Cookie', `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
531
+ ```
532
+
533
+ ```typescript
534
+ export async function deleteUser(userId: string, requesterId: string) {
535
+ const requester = await db.users.findUnique({ where: { id: requesterId } })
536
+ if (requester.role !== 'admin') {
537
+ return NextResponse.json({ error: 'Unauthorized' }, { status: 403 })
538
+ }
539
+ await db.users.delete({ where: { id: userId } })
540
+ }
541
+ ```
542
+
543
+ Row-level security (e.g. Supabase):
544
+
545
+ ```sql
546
+ ALTER TABLE users ENABLE ROW LEVEL SECURITY;
547
+
548
+ CREATE POLICY "Users view own data" ON users FOR SELECT USING (auth.uid() = id);
549
+ CREATE POLICY "Users update own data" ON users FOR UPDATE USING (auth.uid() = id);
550
+ ```
551
+
552
+ Verify: tokens in httpOnly cookies (not localStorage) · authorization checks before sensitive operations · row-level security enabled where supported · role-based access control implemented · session management secure.
553
+
554
+ ## XSS prevention
555
+
556
+ ```typescript
557
+ import DOMPurify from 'isomorphic-dompurify'
558
+
559
+ function renderUserContent(html: string) {
560
+ const clean = DOMPurify.sanitize(html, { ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'], ALLOWED_ATTR: [] })
561
+ return <div dangerouslySetInnerHTML={{ __html: clean }} />
562
+ }
563
+ ```
564
+
565
+ Content-Security-Policy — start strict and loosen only with a documented removal plan; don't default to `'unsafe-inline'` or `'unsafe-eval'`:
566
+
567
+ ```typescript
568
+ const securityHeaders = [{
569
+ key: 'Content-Security-Policy',
570
+ value: `
571
+ default-src 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none';
572
+ script-src 'self'; style-src 'self'; img-src 'self' data: https:; font-src 'self';
573
+ connect-src 'self' https://api.example.com;
574
+ `.replace(/\s{2,}/g, ' ').trim()
575
+ }]
576
+ ```
577
+
578
+ Verify: user-provided HTML sanitized · CSP headers configured · no unvalidated dynamic content rendering · framework's built-in XSS protection used, not bypassed.
579
+
580
+ ## CSRF protection
581
+
582
+ ```typescript
583
+ export async function POST(request: Request) {
584
+ const token = request.headers.get('X-CSRF-Token')
585
+ if (!csrf.verify(token)) return NextResponse.json({ error: 'Invalid CSRF token' }, { status: 403 })
586
+ }
587
+ ```
588
+
589
+ ```typescript
590
+ res.setHeader('Set-Cookie', `session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)
591
+ ```
592
+
593
+ Verify: CSRF tokens on state-changing operations · `SameSite=Strict` on all cookies · double-submit cookie pattern where applicable.
594
+
595
+ ## Rate limiting
596
+
597
+ ```typescript
598
+ import rateLimit from 'express-rate-limit'
599
+
600
+ const limiter = rateLimit({ windowMs: 15 * 60 * 1000, max: 100, message: 'Too many requests' })
601
+ app.use('/api/', limiter)
602
+
603
+ const searchLimiter = rateLimit({ windowMs: 60 * 1000, max: 10, message: 'Too many search requests' })
604
+ app.use('/api/search', searchLimiter)
605
+ ```
606
+
607
+ Verify: rate limiting on all API endpoints · stricter limits on expensive operations · IP-based and, where authenticated, user-based limits.
608
+
609
+ ## Sensitive data exposure
610
+
611
+ ```typescript
612
+ // FAIL
613
+ console.log('User login:', { email, password })
614
+ console.log('Payment:', { cardNumber, cvv })
615
+
616
+ // PASS
617
+ console.log('User login:', { email, userId })
618
+ console.log('Payment:', { last4: card.last4, userId })
619
+ ```
620
+
621
+ ```typescript
622
+ // FAIL
623
+ catch (error) {
624
+ return NextResponse.json({ error: error.message, stack: error.stack }, { status: 500 })
625
+ }
626
+
627
+ // PASS
628
+ catch (error) {
629
+ console.error('Internal error:', error)
630
+ return NextResponse.json({ error: 'An error occurred. Please try again.' }, { status: 500 })
631
+ }
632
+ ```
633
+
634
+ Verify: no passwords/tokens/secrets in logs · error messages generic for users · detailed errors server-side only · no stack traces exposed to users.
635
+
636
+ ## Signed-transaction verification (any system that signs/authorizes value transfer)
637
+
638
+ Wherever a system accepts a signed message or transaction authorizing a transfer of value (payments, on-chain transactions, signed API mutations), verify the signature AND re-check business constraints server-side — never trust a client-reported amount or recipient:
639
+
640
+ ```typescript
641
+ async function verifyTransaction(transaction: Transaction) {
642
+ if (transaction.to !== expectedRecipient) throw new Error('Invalid recipient')
643
+ if (transaction.amount > maxAmount) throw new Error('Amount exceeds limit')
644
+ const balance = await getBalance(transaction.from)
645
+ if (balance < transaction.amount) throw new Error('Insufficient balance')
646
+ return true
647
+ }
648
+ ```
649
+
650
+ Verify: signatures verified · transaction/mutation details re-validated server-side · balance/limit checks before committing · no blind signing of client-supplied payloads.
651
+
652
+ ## Dependency security
653
+
654
+ ```bash
655
+ npm audit
656
+ npm audit fix
657
+ npm update
658
+ npm outdated
659
+ ```
660
+
661
+ ```bash
662
+ git add package-lock.json # always commit lock files
663
+ npm ci # in CI, for reproducible builds
664
+ ```
665
+
666
+ Verify: dependencies up to date · no known vulnerabilities (`npm audit` clean) · lock files committed · automated dependency update tooling enabled · regular security updates.
667
+
668
+ ## Security testing
669
+
670
+ ```typescript
671
+ test('requires authentication', async () => {
672
+ const response = await fetch('/api/protected')
673
+ expect(response.status).toBe(401)
674
+ })
675
+
676
+ test('requires admin role', async () => {
677
+ const response = await fetch('/api/admin', { headers: { Authorization: `Bearer ${userToken}` } })
678
+ expect(response.status).toBe(403)
679
+ })
680
+
681
+ test('rejects invalid input', async () => {
682
+ const response = await fetch('/api/users', { method: 'POST', body: JSON.stringify({ email: 'not-an-email' }) })
683
+ expect(response.status).toBe(400)
684
+ })
685
+
686
+ test('enforces rate limits', async () => {
687
+ const requests = Array(101).fill(null).map(() => fetch('/api/endpoint'))
688
+ const responses = await Promise.all(requests)
689
+ expect(responses.filter(r => r.status === 429).length).toBeGreaterThan(0)
690
+ })
691
+ ```
692
+
693
+ ## Pre-deployment security checklist
694
+
695
+ Before ANY production deployment:
696
+
697
+ - [ ] Secrets: no hardcoded secrets, all in env vars
698
+ - [ ] Input validation: all user inputs validated
699
+ - [ ] SQL injection: all queries parameterized
700
+ - [ ] XSS: user content sanitized
701
+ - [ ] CSRF: protection enabled
702
+ - [ ] Authentication: proper token handling
703
+ - [ ] Authorization: role checks in place
704
+ - [ ] Rate limiting: enabled on all endpoints
705
+ - [ ] HTTPS: enforced in production
706
+ - [ ] Security headers: CSP, X-Frame-Options configured
707
+ - [ ] Error handling: no sensitive data in errors
708
+ - [ ] Logging: no sensitive data logged
709
+ - [ ] Dependencies: up to date, no vulnerabilities
710
+ - [ ] Row-level security: enabled where supported
711
+ - [ ] CORS: properly configured
712
+ - [ ] File uploads: validated (size, type)
713
+ - [ ] Signed transactions: signatures and business constraints re-verified server-side (if applicable)
714
+
715
+ ## Common false positives
716
+
717
+ - Environment variables in `.env.example` (not actual secrets)
718
+ - Test credentials in test files, clearly marked as such
719
+ - Public API keys that are actually meant to be public
720
+ - SHA-256/MD5 used for checksums, not password storage
721
+
722
+ Always verify context before flagging.
723
+
724
+ ## Resources
725
+
726
+ - [OWASP Top 10](https://owasp.org/www-project-top-ten/)
727
+ - [Web Security Academy](https://portswigger.net/web-security)
728
+
729
+ ### security-scan-config
730
+
731
+ Scan this project's AI-harness configuration (settings, CLAUDE.md/AGENTS.md, MCP servers, hooks, agent definitions) for secrets, dangerous permission bypasses, and prompt-injection risk — before committing configuration changes.
732
+
733
+ # Security scan (harness configuration)
734
+
735
+ Scan this project's AI-harness configuration (`.claude/` or equivalent) for security misconfigurations and prompt-injection risk — a separate concern from application code, but part of the same trust boundary in an AI-assisted repo.
736
+
737
+ ## When to activate
738
+
739
+ - Setting up a new AI-harness project configuration
740
+ - After modifying `settings.json`, `CLAUDE.md`/`AGENTS.md`, or MCP server configs
741
+ - Before committing configuration changes
742
+ - When onboarding to a repo with an existing harness configuration
743
+ - Periodic security hygiene checks
744
+
745
+ ## What to review
746
+
747
+ | File | Checks |
748
+ | --- | --- |
749
+ | `CLAUDE.md` / `AGENTS.md` | Hardcoded secrets, auto-run instructions embedded in project docs, prompt-injection patterns |
750
+ | `settings.json` | Overly permissive allow lists, missing deny lists, dangerous bypass flags (e.g. skip-permissions) |
751
+ | MCP server config | Risky/unaudited servers, hardcoded secrets in server env, unpinned `npx`-style install-on-run entries |
752
+ | hooks | Command injection via unescaped interpolation into a shell command, silent error suppression (`2>/dev/null`, `\|\| true`), unexplained outbound network calls |
753
+ | agent definitions | Unrestricted tool access (e.g. unconditional Bash) where the task doesn't need it, missing model spec, prompt-injection surface from untrusted inputs |
754
+
755
+ ## Manual scan (portable, no extra tooling)
756
+
757
+ ```bash
758
+ # hardcoded-looking secrets in harness config
759
+ grep -rEn '(api[_-]?key|secret|token|password)\s*[:=]\s*["\x27][A-Za-z0-9/+=_-]{12,}' .claude/ CLAUDE.md AGENTS.md 2>/dev/null
760
+
761
+ # unrestricted shell / dangerous bypass flags
762
+ grep -rn 'Bash(\*)\|dangerously-skip-permissions\|--no-verify' .claude/settings*.json 2>/dev/null
763
+
764
+ # hook commands that interpolate a file path or tool output directly into a shell string
765
+ grep -rn '${.*}|$(.*)' .claude/settings*.json 2>/dev/null | grep -i hook
766
+
767
+ # silent error suppression in hooks (hides a failing check rather than fixing it)
768
+ grep -rn '2>/dev/null\|\|\| true' .claude/settings*.json 2>/dev/null
769
+ ```
770
+
771
+ ## Severity levels
772
+
773
+ - **CRITICAL** — hardcoded API keys/tokens in config; `Bash(*)` (or equivalent unrestricted shell) in the allow list; command injection in a hook via unescaped interpolation; a shell-executing MCP server with no scoping.
774
+ - **HIGH** — auto-run instructions embedded in project docs (a prompt-injection vector any collaborator's harness will read); missing deny lists on sensitive paths (`~/.ssh`, `~/.aws`, `.env*`); an agent with Bash access it doesn't need for its stated task.
775
+ - **MEDIUM** — silent error suppression in hooks; missing a pre-tool-use security hook on Bash; unpinned install-on-run entries in MCP server config.
776
+ - **INFO** — missing descriptions on MCP servers or agents; explicit prohibitive instructions correctly present (flag as good practice, not a finding).
777
+
778
+ ## Resources
779
+
780
+ - [OWASP MCP Top 10](https://owasp.org/) — tool poisoning, prompt injection via contextual payloads, command injection, shadow MCP servers, secret exposure.