vanara 0.1.0 → 0.3.0

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 (195) hide show
  1. package/README.md +14 -0
  2. package/bin/vanara.js +66 -2
  3. package/catalog/agents/api-designer/AGENT.md +156 -0
  4. package/catalog/agents/api-designer/examples/openapi-snippet.yaml +130 -0
  5. package/catalog/agents/api-designer/examples/review-notes.md +61 -0
  6. package/catalog/agents/api-designer/references/contract-and-openapi.md +82 -0
  7. package/catalog/agents/api-designer/references/design-checklist.md +68 -0
  8. package/catalog/agents/api-designer/references/versioning-and-evolution.md +63 -0
  9. package/catalog/agents/api-designer/scripts/lint-openapi.mjs +180 -0
  10. package/catalog/agents/code-reviewer/AGENT.md +184 -0
  11. package/catalog/agents/code-reviewer/examples/pr-comment-template.md +48 -0
  12. package/catalog/agents/code-reviewer/examples/sample-review-output.md +38 -0
  13. package/catalog/agents/code-reviewer/references/review-checklist.md +46 -0
  14. package/catalog/agents/code-reviewer/references/security-review.md +62 -0
  15. package/catalog/agents/code-reviewer/references/severity-rubric.md +63 -0
  16. package/catalog/agents/code-reviewer/scripts/review-guard.mjs +102 -0
  17. package/catalog/agents/debugger/AGENT.md +128 -0
  18. package/catalog/agents/debugger/examples/postmortem-template.md +59 -0
  19. package/catalog/agents/debugger/examples/repro-template.md +50 -0
  20. package/catalog/agents/debugger/references/bisection.md +63 -0
  21. package/catalog/agents/debugger/references/debugging-method.md +57 -0
  22. package/catalog/agents/debugger/references/observability.md +61 -0
  23. package/catalog/agents/debugger/scripts/parse-stacktrace.mjs +109 -0
  24. package/catalog/agents/pr-summarizer/AGENT.md +172 -0
  25. package/catalog/agents/pr-summarizer/examples/sample-pr-summary.md +46 -0
  26. package/catalog/agents/pr-summarizer/examples/weak-vs-strong-summary.md +68 -0
  27. package/catalog/agents/pr-summarizer/references/identifying-risk.md +68 -0
  28. package/catalog/agents/pr-summarizer/references/reading-the-diff.md +68 -0
  29. package/catalog/agents/pr-summarizer/references/test-plan-and-missing-tests.md +64 -0
  30. package/catalog/agents/pr-summarizer/references/writing-the-summary.md +63 -0
  31. package/catalog/agents/pr-summarizer/scripts/diff-risk.mjs +111 -0
  32. package/catalog/agents/refactoring-specialist/AGENT.md +201 -0
  33. package/catalog/agents/refactoring-specialist/examples/before-after.md +91 -0
  34. package/catalog/agents/refactoring-specialist/examples/refactor-plan.md +97 -0
  35. package/catalog/agents/refactoring-specialist/references/large-scale-refactor.md +50 -0
  36. package/catalog/agents/refactoring-specialist/references/safe-workflow.md +75 -0
  37. package/catalog/agents/refactoring-specialist/references/smell-catalog.md +76 -0
  38. package/catalog/agents/refactoring-specialist/scripts/detect-smells.mjs +150 -0
  39. package/catalog/agents/security-auditor/AGENT.md +184 -0
  40. package/catalog/agents/security-auditor/examples/audit-report.md +68 -0
  41. package/catalog/agents/security-auditor/examples/finding-template.md +31 -0
  42. package/catalog/agents/security-auditor/references/audit-workflow.md +116 -0
  43. package/catalog/agents/security-auditor/references/severity-and-reporting.md +56 -0
  44. package/catalog/agents/security-auditor/references/vuln-classes.md +129 -0
  45. package/catalog/agents/security-auditor/scripts/scan-secrets.mjs +86 -0
  46. package/catalog/agents/technical-writer/AGENT.md +179 -0
  47. package/catalog/agents/technical-writer/examples/how-to-example.md +76 -0
  48. package/catalog/agents/technical-writer/examples/reference-example.md +75 -0
  49. package/catalog/agents/technical-writer/references/clarity-and-style.md +52 -0
  50. package/catalog/agents/technical-writer/references/diataxis-and-doc-types.md +61 -0
  51. package/catalog/agents/technical-writer/references/structure-and-maintenance.md +59 -0
  52. package/catalog/agents/technical-writer/scripts/readability.mjs +103 -0
  53. package/catalog/agents/test-author/AGENT.md +193 -0
  54. package/catalog/agents/test-author/examples/test-plan.md +54 -0
  55. package/catalog/agents/test-author/examples/unit-test-example.ts +55 -0
  56. package/catalog/agents/test-author/references/aaa-and-naming.md +75 -0
  57. package/catalog/agents/test-author/references/mocking-and-fixtures.md +94 -0
  58. package/catalog/agents/test-author/references/test-types-and-pyramid.md +60 -0
  59. package/catalog/agents/test-author/scripts/check-coverage.mjs +145 -0
  60. package/catalog/agents/threat-modeler/AGENT.md +179 -0
  61. package/catalog/agents/threat-modeler/examples/dfd-example.md +55 -0
  62. package/catalog/agents/threat-modeler/examples/threat-model.md +81 -0
  63. package/catalog/agents/threat-modeler/references/dfd-and-trust-boundaries.md +76 -0
  64. package/catalog/agents/threat-modeler/references/mitigation-catalog.md +77 -0
  65. package/catalog/agents/threat-modeler/references/stride-method.md +68 -0
  66. package/catalog/agents/threat-modeler/scripts/stride-checklist.mjs +183 -0
  67. package/catalog/agents/vuln-scanner/AGENT.md +162 -0
  68. package/catalog/agents/vuln-scanner/examples/finding-template.md +57 -0
  69. package/catalog/agents/vuln-scanner/examples/scan-report.md +49 -0
  70. package/catalog/agents/vuln-scanner/references/remediation-and-severity.md +68 -0
  71. package/catalog/agents/vuln-scanner/references/scan-types-and-tools.md +83 -0
  72. package/catalog/agents/vuln-scanner/references/triage-and-false-positives.md +73 -0
  73. package/catalog/agents/vuln-scanner/scripts/parse-scan-results.mjs +133 -0
  74. package/catalog/packs/code-review-pack/PACK.md +100 -0
  75. package/catalog/packs/code-review-pack/examples/pr-flow-example.md +50 -0
  76. package/catalog/packs/code-review-pack/references/rollout-guide.md +40 -0
  77. package/catalog/packs/security-pack/PACK.md +128 -0
  78. package/catalog/packs/security-pack/examples/owasp-vuln-triage-and-fix.md +66 -0
  79. package/catalog/packs/security-pack/examples/threat-model-then-audit.md +77 -0
  80. package/catalog/packs/security-pack/references/choosing-the-right-tool.md +37 -0
  81. package/catalog/packs/security-pack/references/threat-model-to-remediation.md +69 -0
  82. package/catalog/packs/security-pack/references/workflow.md +56 -0
  83. package/catalog/skills/api-pagination/SKILL.md +83 -0
  84. package/catalog/skills/api-pagination/examples/keyset-queries.sql +38 -0
  85. package/catalog/skills/api-pagination/examples/response-shapes.md +51 -0
  86. package/catalog/skills/api-pagination/references/consuming-pages.md +39 -0
  87. package/catalog/skills/api-pagination/references/counting-and-totals.md +41 -0
  88. package/catalog/skills/api-pagination/references/cursor-encoding.md +34 -0
  89. package/catalog/skills/api-pagination/scripts/check-cursor.mjs +51 -0
  90. package/catalog/skills/caching-strategies/SKILL.md +180 -0
  91. package/catalog/skills/caching-strategies/examples/http-cache-headers.md +82 -0
  92. package/catalog/skills/caching-strategies/examples/redis-cache-aside.js +110 -0
  93. package/catalog/skills/caching-strategies/references/cache-patterns.md +93 -0
  94. package/catalog/skills/caching-strategies/references/eviction-and-ttl.md +67 -0
  95. package/catalog/skills/caching-strategies/references/invalidation-and-stampede.md +99 -0
  96. package/catalog/skills/caching-strategies/scripts/ttl-jitter.mjs +99 -0
  97. package/catalog/skills/conventional-commits/SKILL.md +135 -0
  98. package/catalog/skills/conventional-commits/examples/commit-examples.md +60 -0
  99. package/catalog/skills/conventional-commits/examples/commitlint.config.js +31 -0
  100. package/catalog/skills/conventional-commits/references/breaking-changes-semver.md +50 -0
  101. package/catalog/skills/conventional-commits/references/scoping-commits.md +42 -0
  102. package/catalog/skills/conventional-commits/references/spec.md +78 -0
  103. package/catalog/skills/conventional-commits/scripts/lint-commit.mjs +97 -0
  104. package/catalog/skills/database-migrations/SKILL.md +137 -0
  105. package/catalog/skills/database-migrations/examples/add-column-safe.sql +34 -0
  106. package/catalog/skills/database-migrations/examples/migration-config.example.json +27 -0
  107. package/catalog/skills/database-migrations/references/expand-contract.md +74 -0
  108. package/catalog/skills/database-migrations/references/rollback-and-safety.md +71 -0
  109. package/catalog/skills/database-migrations/references/zero-downtime-changes.md +84 -0
  110. package/catalog/skills/database-migrations/scripts/check-migration-reversible.mjs +139 -0
  111. package/catalog/skills/error-handling-patterns/SKILL.md +136 -0
  112. package/catalog/skills/error-handling-patterns/examples/express-error-middleware.js +93 -0
  113. package/catalog/skills/error-handling-patterns/examples/result-pattern.ts +81 -0
  114. package/catalog/skills/error-handling-patterns/references/error-taxonomy.md +91 -0
  115. package/catalog/skills/error-handling-patterns/references/language-patterns.md +102 -0
  116. package/catalog/skills/error-handling-patterns/references/retry-and-backoff.md +76 -0
  117. package/catalog/skills/error-handling-patterns/scripts/lint-empty-catch.mjs +113 -0
  118. package/catalog/skills/git-collaboration-workflows/SKILL.md +104 -0
  119. package/catalog/skills/git-collaboration-workflows/examples/branch-protection.md +48 -0
  120. package/catalog/skills/git-collaboration-workflows/examples/pr-review-playbook.md +48 -0
  121. package/catalog/skills/git-collaboration-workflows/references/branching-models.md +52 -0
  122. package/catalog/skills/git-collaboration-workflows/references/history-hygiene.md +44 -0
  123. package/catalog/skills/git-collaboration-workflows/scripts/check-branch-hygiene.mjs +62 -0
  124. package/catalog/skills/owasp-top10/SKILL.md +112 -0
  125. package/catalog/skills/owasp-top10/examples/sql-injection-fix.md +33 -0
  126. package/catalog/skills/owasp-top10/examples/xss-fix.md +27 -0
  127. package/catalog/skills/owasp-top10/references/access-control.md +36 -0
  128. package/catalog/skills/owasp-top10/references/crypto-failures.md +29 -0
  129. package/catalog/skills/owasp-top10/references/injection.md +39 -0
  130. package/catalog/skills/owasp-top10/references/ssrf-and-design.md +35 -0
  131. package/catalog/skills/owasp-top10/scripts/scan-injection.mjs +73 -0
  132. package/catalog/skills/prompt-engineering/SKILL.md +100 -0
  133. package/catalog/skills/prompt-engineering/examples/classification-prompt.md +29 -0
  134. package/catalog/skills/prompt-engineering/examples/extraction-prompt.md +25 -0
  135. package/catalog/skills/prompt-engineering/references/prompt-injection.md +34 -0
  136. package/catalog/skills/prompt-engineering/references/structured-output.md +34 -0
  137. package/catalog/skills/prompt-engineering/references/techniques.md +33 -0
  138. package/catalog/skills/prompt-engineering/scripts/validate-output.mjs +71 -0
  139. package/catalog/skills/readme-writing/SKILL.md +176 -0
  140. package/catalog/skills/readme-writing/examples/README.template.md +73 -0
  141. package/catalog/skills/readme-writing/examples/good-readme-example.md +95 -0
  142. package/catalog/skills/readme-writing/references/anatomy.md +107 -0
  143. package/catalog/skills/readme-writing/references/maintenance.md +68 -0
  144. package/catalog/skills/readme-writing/references/writing-style.md +79 -0
  145. package/catalog/skills/readme-writing/scripts/lint-readme.mjs +117 -0
  146. package/catalog/skills/refactoring-patterns/SKILL.md +178 -0
  147. package/catalog/skills/refactoring-patterns/examples/extract-function.before-after.js +57 -0
  148. package/catalog/skills/refactoring-patterns/examples/replace-conditional-with-polymorphism.before-after.ts +63 -0
  149. package/catalog/skills/refactoring-patterns/references/code-smells.md +92 -0
  150. package/catalog/skills/refactoring-patterns/references/refactoring-catalog.md +78 -0
  151. package/catalog/skills/refactoring-patterns/references/safe-workflow.md +74 -0
  152. package/catalog/skills/refactoring-patterns/scripts/detect-smells.mjs +137 -0
  153. package/catalog/skills/rest-api-design/SKILL.md +147 -0
  154. package/catalog/skills/rest-api-design/examples/error-envelope.json +26 -0
  155. package/catalog/skills/rest-api-design/examples/orders-api.openapi.yaml +106 -0
  156. package/catalog/skills/rest-api-design/references/error-handling.md +43 -0
  157. package/catalog/skills/rest-api-design/references/pagination.md +41 -0
  158. package/catalog/skills/rest-api-design/references/status-codes.md +32 -0
  159. package/catalog/skills/rest-api-design/references/versioning.md +31 -0
  160. package/catalog/skills/rest-api-design/scripts/check-envelope.mjs +62 -0
  161. package/catalog/skills/secrets-management/SKILL.md +134 -0
  162. package/catalog/skills/secrets-management/examples/env-example.md +41 -0
  163. package/catalog/skills/secrets-management/examples/rotation-runbook.md +50 -0
  164. package/catalog/skills/secrets-management/references/leak-response.md +47 -0
  165. package/catalog/skills/secrets-management/references/rotation.md +46 -0
  166. package/catalog/skills/secrets-management/references/secret-managers.md +52 -0
  167. package/catalog/skills/secrets-management/scripts/detect-hardcoded.mjs +96 -0
  168. package/catalog/skills/secure-auth/SKILL.md +135 -0
  169. package/catalog/skills/secure-auth/examples/auth-flow.md +60 -0
  170. package/catalog/skills/secure-auth/examples/jwt-verify.ts +89 -0
  171. package/catalog/skills/secure-auth/references/auth-attacks.md +76 -0
  172. package/catalog/skills/secure-auth/references/oauth2-oidc.md +65 -0
  173. package/catalog/skills/secure-auth/references/password-hashing.md +70 -0
  174. package/catalog/skills/secure-auth/references/sessions-vs-jwt.md +69 -0
  175. package/catalog/skills/secure-auth/scripts/check-password-policy.mjs +114 -0
  176. package/catalog/skills/sql-index-tuning/SKILL.md +171 -0
  177. package/catalog/skills/sql-index-tuning/examples/explain-walkthrough.sql +91 -0
  178. package/catalog/skills/sql-index-tuning/examples/index-ddl.sql +67 -0
  179. package/catalog/skills/sql-index-tuning/references/btree-internals.md +58 -0
  180. package/catalog/skills/sql-index-tuning/references/composite-and-covering.md +60 -0
  181. package/catalog/skills/sql-index-tuning/references/reading-explain.md +54 -0
  182. package/catalog/skills/sql-index-tuning/references/selectivity-and-cardinality.md +62 -0
  183. package/catalog/skills/sql-index-tuning/scripts/suggest-index.mjs +213 -0
  184. package/catalog/skills/test-plan-design/SKILL.md +154 -0
  185. package/catalog/skills/test-plan-design/examples/test-case-template.md +45 -0
  186. package/catalog/skills/test-plan-design/examples/test-plan.md +57 -0
  187. package/catalog/skills/test-plan-design/references/case-design.md +79 -0
  188. package/catalog/skills/test-plan-design/references/risk-prioritization.md +58 -0
  189. package/catalog/skills/test-plan-design/references/test-pyramid.md +58 -0
  190. package/catalog/skills/test-plan-design/scripts/coverage-gaps.mjs +109 -0
  191. package/free-tier.json +15 -0
  192. package/package.json +15 -4
  193. package/premium-index.json +1 -0
  194. package/src/config.js +31 -1
  195. package/src/license.js +143 -0
@@ -0,0 +1,76 @@
1
+ # Code Smell Catalogue
2
+
3
+ A smell is a surface symptom that usually points to a deeper structural problem. Each entry names the
4
+ smell, how to spot it, and the canonical behavior-preserving refactoring that addresses it. Apply one
5
+ at a time, tests green between each.
6
+
7
+ ## Bloaters
8
+
9
+ ### Long function
10
+ - **Spot it:** more than ~20–50 lines, multiple levels of abstraction in one body, comments that
11
+ section it into "phases".
12
+ - **Fix:** **Extract Function** for each phase; name each by *what* it does, not *how*.
13
+
14
+ ### Large class / module
15
+ - **Spot it:** a file past ~800 lines doing several unrelated jobs.
16
+ - **Fix:** **Extract Class / Extract Module** along responsibility lines; move related fields and the
17
+ methods that use them together.
18
+
19
+ ### Long parameter list
20
+ - **Spot it:** four or more parameters, especially several passed as a group everywhere.
21
+ - **Fix:** **Introduce Parameter Object** or **Preserve Whole Object**.
22
+
23
+ ### Primitive obsession
24
+ - **Spot it:** raw strings/ints carrying domain meaning (a `string currency`, a `number cents`).
25
+ - **Fix:** **Replace Primitive with Value Object**; centralize validation in the new type.
26
+
27
+ ## Conditional complexity
28
+
29
+ ### Deep nesting
30
+ - **Spot it:** arrow-shaped code, 3+ nested `if`s, the happy path buried at the bottom.
31
+ - **Fix:** **Replace Nested Conditional with Guard Clauses**; return/throw early, flatten the rest.
32
+
33
+ ### Switch / type-code dispatch
34
+ - **Spot it:** the same `switch` on a type field repeated in several places.
35
+ - **Fix:** **Replace Conditional with Polymorphism** (or a lookup table / strategy map).
36
+
37
+ ### Repeated boolean expressions
38
+ - **Spot it:** the same compound condition spelled out multiple times.
39
+ - **Fix:** **Extract Function** with an intention-revealing name (`isEligible(order)`).
40
+
41
+ ## Duplication
42
+
43
+ ### Duplicated code
44
+ - **Spot it:** the same statements (or near-identical) in two or more places.
45
+ - **Fix:** **Extract Function** and call it; if duplicated across classes, **Pull Up Method**.
46
+
47
+ ### Shotgun surgery
48
+ - **Spot it:** one logical change forces edits in many scattered files.
49
+ - **Fix:** **Move Method / Move Field** to gather the responsibility into one place.
50
+
51
+ ## Naming and clarity
52
+
53
+ ### Mysterious name
54
+ - **Spot it:** `data2`, `tmp`, `doStuff`, single-letter non-loop variables.
55
+ - **Fix:** **Rename** to reveal intent. Cheap, high value, almost always safe with tooling.
56
+
57
+ ### Comments compensating for unclear code
58
+ - **Spot it:** a comment explaining *what* a block does.
59
+ - **Fix:** **Extract Function** named after the comment, then delete the comment.
60
+
61
+ ## Coupling
62
+
63
+ ### Feature envy
64
+ - **Spot it:** a method that reaches into another object's data more than its own.
65
+ - **Fix:** **Move Method** to the class that owns the data.
66
+
67
+ ### Message chains / inappropriate intimacy
68
+ - **Spot it:** `a.getB().getC().getD()`; objects knowing each other's internals.
69
+ - **Fix:** **Hide Delegate**; expose intent-level methods instead of chains.
70
+
71
+ ## How to use this catalogue
72
+
73
+ 1. Find the smell that matches what you see.
74
+ 2. Confirm tests cover the code (add characterization tests if not).
75
+ 3. Apply only the canonical fix, in small steps, re-running tests after each.
76
+ 4. Stop when the targeted smell is gone — do not chase every smell in the file at once.
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env node
2
+ // Runnable check: scans a string of code for two structural smells this agent
3
+ // targets — long functions and deeply nested blocks — and reports them. It is a
4
+ // heuristic indicator (brace/indent based, language-agnostic), not a parser.
5
+ //
6
+ // Usage:
7
+ // node detect-smells.mjs '<code>' # scan a literal code string
8
+ // echo '<code>' | node detect-smells.mjs # scan from stdin
9
+ // node detect-smells.mjs --selftest # run built-in smelly & clean cases
10
+ //
11
+ // Zero dependencies, Node built-ins only. Exit 0 = no smells found (or selftest
12
+ // passed); exit 1 = smells found (or selftest failed).
13
+
14
+ const MAX_FUNCTION_LINES = 25; // a function body longer than this is "long"
15
+ const MAX_NESTING_DEPTH = 3; // brace depth deeper than this is "deeply nested"
16
+
17
+ // Detect function-like headers across common languages (JS/TS, Python, Go, Java-ish).
18
+ const FUNC_RE = /(\bfunction\b|\bdef\b|=>\s*\{|\bfunc\b|\)\s*\{)/;
19
+
20
+ export function detectSmells(code, opts = {}) {
21
+ const maxLines = opts.maxLines ?? MAX_FUNCTION_LINES;
22
+ const maxDepth = opts.maxDepth ?? MAX_NESTING_DEPTH;
23
+ const lines = String(code).split('\n');
24
+ const smells = [];
25
+
26
+ // --- Deep nesting: track running brace depth ---
27
+ let depth = 0;
28
+ let deepestReported = false;
29
+ lines.forEach((line, i) => {
30
+ const opens = (line.match(/\{/g) || []).length;
31
+ const closes = (line.match(/\}/g) || []).length;
32
+ // depth on this line is measured after opens, before this line's closes apply
33
+ const lineDepth = depth + opens;
34
+ if (lineDepth > maxDepth && !deepestReported) {
35
+ smells.push({
36
+ type: 'deep-nesting',
37
+ line: i + 1,
38
+ message: `nesting depth ${lineDepth} exceeds ${maxDepth} (consider guard clauses / extract function)`,
39
+ });
40
+ deepestReported = true; // report once to avoid noise
41
+ }
42
+ depth += opens - closes;
43
+ if (depth < 0) depth = 0;
44
+ });
45
+
46
+ // --- Long functions: measure span from a function header to its matching close,
47
+ // or (brace-less languages) to the next blank line / dedent boundary. ---
48
+ for (let i = 0; i < lines.length; i++) {
49
+ if (!FUNC_RE.test(lines[i])) continue;
50
+ const span = spanOfFunction(lines, i);
51
+ if (span > maxLines) {
52
+ smells.push({
53
+ type: 'long-function',
54
+ line: i + 1,
55
+ message: `function spans ${span} lines, exceeds ${maxLines} (consider extract function)`,
56
+ });
57
+ }
58
+ i += Math.max(0, span - 1); // skip past the counted body
59
+ }
60
+
61
+ return { ok: smells.length === 0, smells };
62
+ }
63
+
64
+ function spanOfFunction(lines, start) {
65
+ const header = lines[start];
66
+ if (header.includes('{')) {
67
+ // brace-counted span
68
+ let depth = 0, seen = false;
69
+ for (let j = start; j < lines.length; j++) {
70
+ depth += (lines[j].match(/\{/g) || []).length;
71
+ depth -= (lines[j].match(/\}/g) || []).length;
72
+ if (depth > 0) seen = true;
73
+ if (seen && depth <= 0) return j - start + 1;
74
+ }
75
+ return lines.length - start;
76
+ }
77
+ // brace-less (e.g. Python): count until a blank line or a dedent to column 0
78
+ const baseIndent = indentOf(header);
79
+ let j = start + 1;
80
+ for (; j < lines.length; j++) {
81
+ const ln = lines[j];
82
+ if (ln.trim() === '') break;
83
+ if (indentOf(ln) <= baseIndent && ln.trim() !== '') break;
84
+ }
85
+ return j - start;
86
+ }
87
+
88
+ function indentOf(line) {
89
+ const m = line.match(/^(\s*)/);
90
+ return m ? m[1].length : 0;
91
+ }
92
+
93
+ function report(label, code) {
94
+ const { ok, smells } = detectSmells(code);
95
+ if (ok) {
96
+ console.log(`✓ ${label}: no structural smells detected`);
97
+ } else {
98
+ console.error(`✗ ${label}: ${smells.length} smell(s) found`);
99
+ for (const s of smells) console.error(` - [${s.type}] line ${s.line}: ${s.message}`);
100
+ }
101
+ return ok;
102
+ }
103
+
104
+ function selftest() {
105
+ const smelly = [
106
+ 'function f(a) {',
107
+ ' if (a) {',
108
+ ' if (a.b) {',
109
+ ' if (a.b.c) {', // depth 4 -> deep nesting
110
+ ' return a.b.c;',
111
+ ' }',
112
+ ' }',
113
+ ' }',
114
+ '}',
115
+ ].join('\n');
116
+
117
+ const longFn = 'function big() {\n' + Array.from({ length: 30 }, (_, i) => ` const x${i} = ${i};`).join('\n') + '\n}';
118
+
119
+ const clean = [
120
+ 'function priceFor(order) {',
121
+ ' if (order == null) throw new Error("no order");',
122
+ ' if (order.items.length === 0) throw new Error("empty");',
123
+ ' return order.subtotal - order.discount;',
124
+ '}',
125
+ ].join('\n');
126
+
127
+ const cases = [
128
+ ['smelly_nesting', smelly, false],
129
+ ['smelly_long_function', longFn, false],
130
+ ['clean', clean, true],
131
+ ];
132
+
133
+ let allPass = true;
134
+ for (const [name, code, expectOk] of cases) {
135
+ const { ok } = detectSmells(code);
136
+ const correct = ok === expectOk;
137
+ allPass &&= correct;
138
+ console.log(`${correct ? '✓' : '✗'} selftest ${name}: ${ok ? 'clean' : 'smelly'} (expected ${expectOk ? 'clean' : 'smelly'})`);
139
+ }
140
+ process.exit(allPass ? 0 : 1);
141
+ }
142
+
143
+ const arg = process.argv[2];
144
+ if (arg === '--selftest') selftest();
145
+ else if (arg) process.exit(report('code', arg) ? 0 : 1);
146
+ else {
147
+ let buf = '';
148
+ process.stdin.on('data', (c) => (buf += c));
149
+ process.stdin.on('end', () => process.exit(report('stdin', buf) ? 0 : 1));
150
+ }
@@ -0,0 +1,184 @@
1
+ ---
2
+ name: security-auditor
3
+ description: Use PROACTIVELY before commits/merges and whenever code touches auth, user input, secrets, file paths, DB queries, deserialization, or outbound requests. Audits against the OWASP Top 10, traces untrusted data to dangerous sinks, and reports vulnerabilities by severity with concrete fixes and a merge verdict.
4
+ tools: Read, Grep, Glob, Bash
5
+ model: claude-sonnet-4-6
6
+ type: agent
7
+ version: 2.0.0
8
+ updated: 2026-06-29
9
+ ---
10
+ # Security Auditor
11
+
12
+ You are a **senior application security engineer running a focused code audit**. Your job is to find
13
+ exploitable vulnerabilities *before an attacker does* — and to prove each one is real by tracing how
14
+ untrusted input reaches a dangerous sink. You think in terms of **data flow and trust boundaries**,
15
+ not whether the code "looks tidy". A linter checks style; you check whether the system can be broken.
16
+
17
+ An audit is **trustworthy** when every finding is exploitable, anchored to a specific `file:line`,
18
+ mapped to an OWASP category, and shipped with a minimal, correct fix. That is the bar. If a surface is
19
+ clean, you say so plainly — you do not manufacture findings to look thorough.
20
+
21
+ ## Role and operating principles
22
+
23
+ - **Source-to-sink reasoning.** A vulnerability exists when *attacker-controlled* data reaches a
24
+ *dangerous sink* without a *neutralizing control* in between. Name all three for every finding.
25
+ - **Exploit before you escalate.** If you can't describe a concrete attack (the input, the path, the
26
+ impact), it is not CRITICAL/HIGH. Downgrade or cut it.
27
+ - **Allow-list over block-list.** Recommend parameterization, output encoding, and allow-lists. A
28
+ blocklist of "bad characters" is a finding, not a fix.
29
+ - **Fail closed.** Missing authorization, default-allow branches, and swallowed auth errors are
30
+ vulnerabilities even with no working exploit yet — they are latent ones.
31
+ - **Never weaken a control to silence a finding.** If a secret is exposed, the fix includes *rotating*
32
+ it, not just deleting the line.
33
+
34
+ ## OWASP-driven audit workflow
35
+
36
+ Work the surface in this order. Do not jump to crypto trivia before checking access control.
37
+
38
+ 1. **Map the attack surface.** Enumerate entry points (HTTP routes, form/JSON/query params, headers,
39
+ file uploads, webhooks, message consumers, CLI args, env) and dangerous sinks (SQL/NoSQL queries,
40
+ `exec`/`spawn`, filesystem paths, HTML/template rendering, outbound HTTP, deserializers, redirects).
41
+ Use `Grep`/`Glob` to locate them fast. This map drives the whole audit.
42
+ 2. **Broken access control (A01).** For every protected action, verify the code checks *ownership*,
43
+ not just authentication. Hunt IDOR (object id from the request used without an ownership check),
44
+ missing role checks, and forced-browsing on admin routes. This is the #1 OWASP risk — do it first.
45
+ 3. **Injection (A03).** Trace each untrusted input to its sink: SQL/NoSQL (string-built queries),
46
+ OS command (`exec`/`system`), template/SSTI, XSS (unescaped output / `innerHTML` /
47
+ `dangerouslySetInnerHTML`), LDAP, header injection. See `references/vuln-classes.md`.
48
+ 4. **Secrets & cryptographic failures (A02/A07).** Run `scripts/scan-secrets.mjs` over changed files
49
+ to catch hardcoded keys/tokens/private keys. Check for weak hashing (MD5/SHA1 for passwords),
50
+ missing salt, `==` token comparison (timing attack), and secrets in logs.
51
+ 5. **SSRF, path traversal, open redirect (A01/A10).** Any user-influenced URL, hostname, or file path
52
+ reaching a fetch/open/redirect sink without an allow-list is a finding.
53
+ 6. **Insecure deserialization & unsafe sinks (A08).** `pickle`, `yaml.load`, `eval`, native
54
+ `Deserialize`, prototype pollution. Untrusted bytes into a deserializer is RCE-adjacent.
55
+ 7. **Security misconfiguration & dependencies (A05/A06).** Debug mode in prod, permissive CORS
56
+ (`*` with credentials), missing security headers, known-vulnerable dependency versions.
57
+ 8. **Self-check (maker-checker).** Re-read every finding. Can you state the input, the path, and the
58
+ impact? Does the line exist? Is the fix correct and minimal? Delete what you cannot defend.
59
+
60
+ The full step-by-step procedure with grep recipes is in `references/audit-workflow.md`.
61
+
62
+ ## Severity rubric
63
+
64
+ Assign exactly one severity per finding. Full rubric and reporting rules in
65
+ `references/severity-and-reporting.md`; the summary:
66
+
67
+ | Severity | Meaning | Required action |
68
+ |---|---|---|
69
+ | **CRITICAL** | Remote exploit, RCE, auth bypass, or mass data exposure | **Block merge.** Fix now. |
70
+ | **HIGH** | Real vuln needing some condition (auth, specific input) | Fix before merge. |
71
+ | **MEDIUM** | Weakness with limited impact or defense-in-depth gap | Should fix. |
72
+ | **LOW** | Hardening / best-practice nit, no direct exploit | Optional. |
73
+
74
+ End every audit with one verdict: **Go** / **Go-with-fixes** / **No-go (block)**.
75
+
76
+ ## Output format
77
+
78
+ Group findings by severity, highest first. Each finding is a single block with a `file:line` anchor,
79
+ the OWASP category, a concrete exploit scenario, and the fix.
80
+
81
+ ```md
82
+ ## Security Audit — <component / branch>
83
+
84
+ ### CRITICAL
85
+ - `orders/repo.js:88` — **SQL injection (A03)**. `sort` from the query string is concatenated into
86
+ the SQL text: `ORDER BY ${req.query.sort}`. Exploit: `?sort=id;DROP TABLE orders--`.
87
+ **Fix:** allow-list sortable columns (`{created_at, total}`) and bind values as parameters; never
88
+ interpolate identifiers.
89
+
90
+ ### HIGH
91
+ - `users/controller.js:31` — **Broken access control / IDOR (A01)**. `findByUser(req.params.id)`
92
+ with no ownership check; any logged-in user reads others' invoices via `:id`.
93
+ **Fix:** `if (req.params.id !== req.session.userId) return res.status(404).end();` then query.
94
+
95
+ **Verdict: No-go** — 1 critical, 1 high block merge. Rotate any DB creds if injection was reachable.
96
+ ```
97
+
98
+ ### Worked example: vulnerability → fix
99
+
100
+ Given this handler:
101
+
102
+ ```js
103
+ // reports/controller.js
104
+ app.get('/reports', (req, res) => {
105
+ const file = req.query.name; // attacker-controlled
106
+ const data = fs.readFileSync(`/var/reports/${file}`); // dangerous sink
107
+ res.type('text/plain').send(data);
108
+ });
109
+ ```
110
+
111
+ The finding and remediation:
112
+
113
+ ```md
114
+ ### CRITICAL
115
+ - `reports/controller.js:4` — **Path traversal (A01)**. `name` is concatenated into a filesystem
116
+ path with no normalization. Exploit: `GET /reports?name=../../../etc/passwd` reads arbitrary files.
117
+ **Fix:** resolve and confine to the base dir, and allow-list the filename:
118
+ const base = path.resolve('/var/reports');
119
+ const target = path.resolve(base, path.basename(file));
120
+ if (!target.startsWith(base + path.sep)) return res.status(400).end();
121
+ Use `path.basename` to strip directory components and verify the resolved path stays under `base`.
122
+ ```
123
+
124
+ ## Common pitfalls (failure modes to avoid)
125
+
126
+ - **Reporting "tainted input" with no sink.** Input you can't trace to a dangerous operation is not a
127
+ vulnerability. Always name the sink and the impact.
128
+ - **Confusing authentication with authorization.** "The route requires login" does not mean the user
129
+ may touch *this* object. IDOR lives in that gap — check ownership explicitly.
130
+ - **Recommending a blocklist.** "Strip `<script>`" / "reject `;`" is bypassable. Push parameterization,
131
+ contextual output encoding, and allow-lists instead.
132
+ - **Severity inflation.** Marking a missing security header CRITICAL, or a real SQL injection MEDIUM,
133
+ destroys the audit's credibility. Calibrate against the rubric.
134
+ - **Stopping at the first bug.** One injection rarely travels alone. Finish the full surface map; the
135
+ same unsafe pattern is usually copied across handlers.
136
+ - **Forgetting rotation.** Deleting a committed secret does not un-leak it — git history still holds
137
+ it. The fix is *rotate the credential*, then remove and use a secret manager.
138
+ - **Trusting client-side checks.** Validation in the browser is UX, not security. Every control must
139
+ be re-enforced server-side.
140
+
141
+ ## When NOT to use / boundaries
142
+
143
+ - **Not a SAST/dependency scanner.** For exhaustive automated coverage, run dedicated tooling (the
144
+ `vuln-scanner` agent / `semgrep` / `npm audit`). You do targeted human-grade source-to-sink review.
145
+ - **Not a build or test fixer.** Failing builds go to the `build-error-resolver` agent; you assess
146
+ security, not compiler errors.
147
+ - **Not threat modeling.** For trust-boundary diagrams, attacker personas, and system-level abuse
148
+ cases *before* code exists, use the `threat-modeler` agent — that is design-time; you are code-time.
149
+ - **Not a penetration test.** You read code; you do not run live exploits against production. Findings
150
+ are evidence-based static reasoning, optionally confirmed in a sandbox.
151
+ - **Not a secret rotator.** You *detect and instruct*; actual rotation happens in the secret manager
152
+ and CI by the owning team.
153
+
154
+ ## Files in this package
155
+
156
+ - `AGENT.md` — this system prompt: role, OWASP workflow, severity rubric, output format, boundaries.
157
+ - `references/audit-workflow.md` — the full step-by-step audit procedure with grep recipes per phase.
158
+ - `references/vuln-classes.md` — injection, broken access control/IDOR, secrets, deserialization,
159
+ SSRF, path traversal, XSS — signatures, exploits, and fixes for each.
160
+ - `references/severity-and-reporting.md` — severity calibration, OWASP mapping, and the report contract.
161
+ - `examples/audit-report.md` — a complete worked audit in the standard format.
162
+ - `examples/finding-template.md` — copy-paste single-finding template.
163
+ - `scripts/scan-secrets.mjs` — runnable Node check that regex-scans a code string for hardcoded
164
+ secrets (AWS keys, API tokens, private keys); run with `--selftest` (exit 0/1).
165
+
166
+ **Pairs with** the [`threat-modeler`](../threat-modeler/AGENT.md) agent for design-time trust-boundary
167
+ analysis, the [`vuln-scanner`](../vuln-scanner/AGENT.md) agent for automated SAST/dependency coverage, and
168
+ the `owasp-top10` skill for the full vulnerability catalogue.
169
+
170
+
171
+ ## Memory — learn across sessions
172
+
173
+ You keep a persistent, per-project memory at `.claude/memory/security-auditor.md`. It is
174
+ how you get sharper on *this* codebase over time instead of starting cold every run.
175
+
176
+ - **Before you start:** read `.claude/memory/security-auditor.md` if it exists and apply what
177
+ it holds — corrections you were given before, this project's conventions, decisions
178
+ and their rationale, and recurring pitfalls. If it is missing, continue without it.
179
+ - **After you finish:** if this task taught you something durable — a correction from
180
+ the user, a project-specific convention, a mistake worth not repeating — append it as
181
+ a short dated bullet under a relevant heading, and prune anything now stale or wrong.
182
+ Keep entries terse and general.
183
+ - **Never record** secrets, credentials, tokens, personal data, or one-off trivia, and
184
+ never write anywhere except your own `.claude/memory/` file.
@@ -0,0 +1,68 @@
1
+ # Example: Full Security Audit Report
2
+
3
+ A complete, realistic audit of a small Express orders service, in the standard format. Use it as the
4
+ shape your output should take. (Secret values shown are obviously fake illustrations.)
5
+
6
+ ---
7
+
8
+ ## Security Audit — `orders-service` (branch `feat/order-export`)
9
+
10
+ Scope: 4 changed files — `orders/controller.js`, `orders/repo.js`, `reports/controller.js`,
11
+ `config.js`. Surfaces: 3 HTTP routes (1 public, 2 authenticated), 1 SQL data layer, 1 file read, 1
12
+ config module.
13
+
14
+ ### CRITICAL
15
+
16
+ - `orders/repo.js:88` — **SQL injection (A03)**. `req.query.sort` is interpolated into the query
17
+ (`ORDER BY ${sort}`). Exploit: `GET /orders?sort=id;DROP TABLE orders--`. **Fix:** allow-list
18
+ sortable columns and bind values:
19
+ ```js
20
+ const COLS = { created_at: 'created_at', total: 'total' };
21
+ const col = COLS[req.query.sort] ?? 'created_at';
22
+ db.query(`SELECT * FROM orders WHERE owner = ? ORDER BY ${col} DESC LIMIT 50`, [req.session.userId]);
23
+ ```
24
+
25
+ - `reports/controller.js:12` — **Path traversal (A01)**. `req.query.name` is concatenated into a file
26
+ path read and returned. Exploit: `GET /reports?name=../../../../etc/passwd`. **Fix:** confine to a
27
+ base dir and strip components:
28
+ ```js
29
+ const base = path.resolve('/var/reports');
30
+ const target = path.resolve(base, path.basename(req.query.name));
31
+ if (!target.startsWith(base + path.sep)) return res.status(400).end();
32
+ ```
33
+
34
+ ### HIGH
35
+
36
+ - `orders/controller.js:34` — **Broken access control / IDOR (A01)**. `GET /orders/:id` fetches by id
37
+ with no ownership check; any authenticated user reads any order. **Fix:** compare to the session
38
+ principal and 404 on mismatch:
39
+ ```js
40
+ const order = await repo.findById(req.params.id);
41
+ if (!order || order.ownerId !== req.session.userId) return res.status(404).end();
42
+ ```
43
+
44
+ - `config.js:7` — **Hardcoded secret / cryptographic failure (A02)**. A live-looking API token is
45
+ committed: `const STRIPE = 'sk_live_4eC39HqLyjEXAMPLEzdp7dc'` (fake illustration). **Fix:** load from
46
+ env/secret manager and **rotate** the token — git history still contains it. Add a pre-commit secret
47
+ scan (`scripts/scan-secrets.mjs`).
48
+
49
+ ### MEDIUM
50
+
51
+ - `orders/controller.js:9` — **Security misconfiguration (A05)**. Errors return the full stack trace to
52
+ the client (`res.status(500).send(err.stack)`), leaking file paths and library versions. **Fix:**
53
+ return a generic message; log the detail server-side.
54
+
55
+ ### LOW
56
+
57
+ - `config.js:1` — **Missing hardening (A05)**. No security headers are set (CSP, HSTS,
58
+ X-Content-Type-Options). **Fix:** add a headers middleware (e.g. `helmet`).
59
+
60
+ ---
61
+
62
+ **Verdict: No-go (block)** — 2 CRITICAL and 2 HIGH must be fixed before merge.
63
+
64
+ **Remediation notes:**
65
+ - Rotate the Stripe token immediately; deleting the line does not un-leak it (history retains it).
66
+ - The injection and traversal share a root cause — request data reaching a sink unsanitized. Sweep the
67
+ other controllers for the same pattern; it is usually copied.
68
+ - Re-audit after fixes; verify the IDOR fix returns 404 (not 403) to avoid leaking order existence.
@@ -0,0 +1,31 @@
1
+ # Single-Finding Template
2
+
3
+ Copy this block per finding. Keep it to one anchor, one exploit sentence, one fix. Delete the guidance
4
+ comments before shipping.
5
+
6
+ ```md
7
+ ### <CRITICAL | HIGH | MEDIUM | LOW>
8
+ - `<path>:<line>` — **<Vulnerability name> (<OWASP category, e.g. A03>)**. <One sentence: which
9
+ attacker-controlled input reaches which dangerous sink, and the concrete impact. Include the exploit
10
+ string if it makes it real.> **Fix:** <the corrected code or precise action — a real control
11
+ (parameterize / encode / allow-list / rotate), never a blocklist.>
12
+ ```
13
+
14
+ ## Filled example
15
+
16
+ ```md
17
+ ### CRITICAL
18
+ - `orders/repo.js:88` — **SQL injection (A03)**. The `sort` query param is interpolated into the SQL
19
+ text (`ORDER BY ${req.query.sort}`); `?sort=id;DROP TABLE orders--` executes arbitrary SQL.
20
+ **Fix:** allow-list sortable columns (`{ created_at, total }`) and map the param through it; bind
21
+ all values as parameters. Identifiers can't be bound, so the allow-list is mandatory.
22
+ ```
23
+
24
+ ## Checklist before you ship a finding
25
+
26
+ - [ ] Anchored to a real `file:line` that contains the quoted code.
27
+ - [ ] Names the source (input), the sink, and the impact.
28
+ - [ ] Has an OWASP category.
29
+ - [ ] Severity matches the rubric in `../references/severity-and-reporting.md`.
30
+ - [ ] Fix is a real control, not a blocklist; includes rotation if a secret was exposed.
31
+ - [ ] You could defend it to the author without hand-waving.
@@ -0,0 +1,116 @@
1
+ # Audit Workflow — Step by Step
2
+
3
+ This is the detailed procedure behind the workflow summarized in `AGENT.md`. Work top to bottom; each
4
+ phase produces findings you carry into the report. The governing rule is **source → sink → control**:
5
+ a vulnerability exists only when attacker-controlled data reaches a dangerous operation without a
6
+ neutralizing control in between.
7
+
8
+ ## Phase 0 — Establish scope
9
+
10
+ 1. Determine the change set: `git diff <base>...HEAD --stat`, or read the modified files directly.
11
+ 2. Identify the security-relevant surfaces in scope: auth, input handling, data access, file I/O,
12
+ outbound requests, deserialization, templating, secrets/config.
13
+ 3. Note the trust level of each entry: fully public, authenticated, admin-only, internal service.
14
+
15
+ ## Phase 1 — Map the attack surface
16
+
17
+ Build two lists. Use `Grep`/`Glob` to populate them quickly.
18
+
19
+ **Entry points (sources of untrusted data):**
20
+ ```
21
+ req.body | req.query | req.params | req.headers | req.cookies # web inputs
22
+ multipart / file upload handlers # uploaded bytes
23
+ process.argv | process.env # CLI / env
24
+ message/queue consumers, webhook handlers # async inputs
25
+ ```
26
+
27
+ **Dangerous sinks:**
28
+ ```
29
+ query( | execute( | raw( | `SELECT ... ${ # SQL/NoSQL
30
+ exec( | execSync( | spawn( | system( # OS command
31
+ fs.readFile | fs.writeFile | path.join(.*req # filesystem
32
+ innerHTML | dangerouslySetInnerHTML | res.send(.*req | render( # HTML/XSS/SSTI
33
+ fetch( | axios( | http.get( | requests.get( # outbound / SSRF
34
+ pickle.loads | yaml.load | eval( | JSON-with-reviver | Deserialize # deserialization
35
+ res.redirect( | Location: # open redirect
36
+ ```
37
+
38
+ A finding is born wherever a Phase-1 source feeds a Phase-1 sink. The rest of the workflow checks
39
+ each pairing for a neutralizing control.
40
+
41
+ ## Phase 2 — Broken access control (OWASP A01) — do this FIRST
42
+
43
+ A01 is the most common real-world breach class. For every state-changing or data-returning action:
44
+
45
+ 1. Is there an authentication check? (Necessary, not sufficient.)
46
+ 2. Is there an **authorization** check that the *current principal* may act on *this specific object*?
47
+ - IDOR test: take any handler that reads `req.params.id` / `req.body.userId` and look for an
48
+ ownership comparison against the session principal. If absent → finding.
49
+ 3. Are admin/privileged routes guarded by a role check, not just by being "unlinked" in the UI?
50
+ 4. Are there default-allow branches (`if (denied) {...}` with an implicit allow fall-through)?
51
+
52
+ Grep starters:
53
+ ```
54
+ findBy.*req.params | findById\(req | where.*req.body.*id
55
+ isAdmin | role === | hasPermission | can\( # confirm these actually gate the action
56
+ ```
57
+
58
+ ## Phase 3 — Injection (A03)
59
+
60
+ Trace each untrusted input to its sink and confirm a parameterizing/encoding control exists.
61
+
62
+ - **SQL/NoSQL:** any query assembled with string concatenation or template literals containing
63
+ request data. Fix = parameterized queries / prepared statements; allow-list identifiers (columns,
64
+ table names, sort direction) since those can't be bound.
65
+ - **OS command:** request data in `exec`/`spawn`/`system`. Fix = avoid the shell; pass an argv array
66
+ to `execFile`; allow-list the command and arguments.
67
+ - **XSS:** request data rendered into HTML without contextual encoding; `innerHTML`,
68
+ `dangerouslySetInnerHTML`, unescaped template interpolation. Fix = contextual output encoding;
69
+ framework auto-escaping; sanitize with a vetted library only when raw HTML is unavoidable.
70
+ - **Template injection (SSTI):** user input concatenated into a template *string* (not passed as
71
+ data). Fix = pass user data as template variables, never build the template from it.
72
+
73
+ See `vuln-classes.md` for per-class exploit strings and fixes.
74
+
75
+ ## Phase 4 — Secrets & cryptographic failures (A02/A07)
76
+
77
+ 1. Run `node scripts/scan-secrets.mjs "<code>"` (or pipe files) over changed content to catch
78
+ hardcoded AWS keys, bearer/API tokens, and private-key blocks.
79
+ 2. Password storage: must use a slow KDF (bcrypt/scrypt/argon2) with a per-user salt. MD5/SHA1/SHA256
80
+ for passwords = finding.
81
+ 3. Token/secret comparison: `a == b` on secrets is timing-attackable. Fix = constant-time compare.
82
+ 4. Secrets in logs, error messages, or URLs (query strings get logged) = finding.
83
+ 5. If any secret is found committed, the remediation **includes rotating it** — git history retains
84
+ the old value even after deletion.
85
+
86
+ ## Phase 5 — SSRF, path traversal, open redirect (A01/A10)
87
+
88
+ - **SSRF:** user-influenced URL/host reaching an outbound fetch. Fix = allow-list of permitted hosts;
89
+ block private/link-local ranges and metadata IPs (`169.254.169.254`); resolve-then-validate.
90
+ - **Path traversal:** user input in a filesystem path. Fix = `path.basename` to strip components,
91
+ `path.resolve` against a fixed base, then assert the resolved path stays under the base dir.
92
+ - **Open redirect:** user-controlled redirect target. Fix = allow-list of relative paths / known hosts.
93
+
94
+ ## Phase 6 — Insecure deserialization & unsafe sinks (A08)
95
+
96
+ Untrusted bytes into `pickle.loads`, `yaml.load` (use `safe_load`), `eval`, `Function()`, or native
97
+ binary deserializers is a critical RCE class. Also check prototype pollution (`obj[userKey] = val` /
98
+ unfiltered `Object.assign` from request bodies). Fix = safe parsers, schema validation, never
99
+ deserialize untrusted data into live objects.
100
+
101
+ ## Phase 7 — Misconfiguration & dependencies (A05/A06)
102
+
103
+ - Debug mode / stack traces exposed in production.
104
+ - CORS `Access-Control-Allow-Origin: *` combined with credentials.
105
+ - Missing security headers (CSP, HSTS, X-Content-Type-Options, X-Frame-Options).
106
+ - Known-vulnerable dependency versions (cross-check lockfile against advisories).
107
+
108
+ ## Phase 8 — Self-check (maker-checker)
109
+
110
+ For each finding, before it goes in the report:
111
+ - Can you state the **input**, the **path**, and the **impact** in one sentence?
112
+ - Does the cited `file:line` exist and contain the quoted code?
113
+ - Is the proposed fix correct, minimal, and a real control (not a blocklist)?
114
+ - Is the severity defensible against the rubric?
115
+
116
+ Cut anything that fails. A short audit of real findings beats a long one padded with guesses.