ship-safe 6.1.0 → 6.2.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 (48) hide show
  1. package/README.md +735 -594
  2. package/cli/agents/api-fuzzer.js +345 -345
  3. package/cli/agents/auth-bypass-agent.js +348 -348
  4. package/cli/agents/base-agent.js +272 -272
  5. package/cli/agents/cicd-scanner.js +236 -201
  6. package/cli/agents/config-auditor.js +521 -521
  7. package/cli/agents/deep-analyzer.js +6 -2
  8. package/cli/agents/git-history-scanner.js +170 -170
  9. package/cli/agents/html-reporter.js +40 -4
  10. package/cli/agents/index.js +84 -84
  11. package/cli/agents/injection-tester.js +500 -500
  12. package/cli/agents/llm-redteam.js +251 -251
  13. package/cli/agents/mobile-scanner.js +231 -231
  14. package/cli/agents/orchestrator.js +322 -322
  15. package/cli/agents/pii-compliance-agent.js +301 -301
  16. package/cli/agents/scoring-engine.js +248 -248
  17. package/cli/agents/supabase-rls-agent.js +154 -154
  18. package/cli/agents/supply-chain-agent.js +650 -507
  19. package/cli/bin/ship-safe.js +452 -426
  20. package/cli/commands/agent.js +608 -608
  21. package/cli/commands/audit.js +986 -979
  22. package/cli/commands/baseline.js +193 -193
  23. package/cli/commands/ci.js +342 -342
  24. package/cli/commands/deps.js +516 -516
  25. package/cli/commands/doctor.js +159 -159
  26. package/cli/commands/fix.js +218 -218
  27. package/cli/commands/hooks.js +268 -0
  28. package/cli/commands/init.js +407 -407
  29. package/cli/commands/mcp.js +304 -304
  30. package/cli/commands/red-team.js +7 -1
  31. package/cli/commands/remediate.js +798 -798
  32. package/cli/commands/rotate.js +571 -571
  33. package/cli/commands/scan.js +569 -567
  34. package/cli/commands/score.js +449 -448
  35. package/cli/commands/watch.js +281 -281
  36. package/cli/hooks/patterns.js +313 -0
  37. package/cli/hooks/post-tool-use.js +140 -0
  38. package/cli/hooks/pre-tool-use.js +186 -0
  39. package/cli/index.js +73 -69
  40. package/cli/providers/llm-provider.js +397 -287
  41. package/cli/utils/autofix-rules.js +74 -74
  42. package/cli/utils/cache-manager.js +311 -311
  43. package/cli/utils/output.js +1 -0
  44. package/cli/utils/patterns.js +1121 -1121
  45. package/cli/utils/pdf-generator.js +94 -94
  46. package/package.json +69 -68
  47. package/cli/__tests__/agents.test.js +0 -1301
  48. package/configs/supabase/rls-templates.sql +0 -242
@@ -1,500 +1,500 @@
1
- /**
2
- * InjectionTester Agent
3
- * ======================
4
- *
5
- * Detects injection vulnerabilities by tracing data flow patterns
6
- * from user input to dangerous sinks.
7
- *
8
- * Covers: SQL Injection, NoSQL Injection, Command Injection,
9
- * Code Injection, XSS, LDAP Injection, Template Injection,
10
- * Header Injection, Path Traversal, Log Injection,
11
- * GraphQL Injection, Open Redirect.
12
- */
13
-
14
- import path from 'path';
15
- import { BaseAgent, createFinding } from './base-agent.js';
16
-
17
- // =============================================================================
18
- // INJECTION PATTERNS
19
- // =============================================================================
20
-
21
- const PATTERNS = [
22
- // ── SQL Injection ──────────────────────────────────────────────────────────
23
- {
24
- rule: 'SQL_INJECTION_TEMPLATE_LITERAL',
25
- title: 'SQL Injection via Template Literal',
26
- regex: /`(?:SELECT|INSERT|UPDATE|DELETE|DROP\s+TABLE|ALTER\s+TABLE|TRUNCATE|CREATE|REPLACE|MERGE)[^`]*\$\{/gi,
27
- severity: 'critical',
28
- cwe: 'CWE-89',
29
- owasp: 'A03:2021',
30
- description: 'SQL query with interpolated template variable. Use parameterized queries ($1, ?) or an ORM.',
31
- fix: 'Use parameterized queries: db.query("SELECT * FROM users WHERE id = $1", [userId])',
32
- },
33
- {
34
- rule: 'SQL_INJECTION_CONCAT',
35
- title: 'SQL Injection via String Concatenation',
36
- regex: /["'](?:SELECT|INSERT|UPDATE|DELETE)\s+[^"']{4,}["']\s*\+/gi,
37
- severity: 'high',
38
- cwe: 'CWE-89',
39
- owasp: 'A03:2021',
40
- description: 'SQL built with string concatenation is vulnerable to injection. Use parameterized queries.',
41
- fix: 'Replace string concat with parameterized query or ORM method',
42
- },
43
- {
44
- rule: 'SQL_INJECTION_RAW',
45
- title: 'Raw SQL Query (Prisma/Sequelize/Knex)',
46
- regex: /(?:\$queryRaw|\.raw|knex\.raw)\s*\(\s*`[^`]*\$\{/gi,
47
- severity: 'critical',
48
- cwe: 'CWE-89',
49
- owasp: 'A03:2021',
50
- description: 'ORM raw query with interpolated values bypasses parameterization. Use tagged templates or bind parameters.',
51
- fix: 'Prisma: use $queryRaw`...${Prisma.sql}...`; Sequelize: use bind parameters',
52
- },
53
-
54
- // ── NoSQL Injection ────────────────────────────────────────────────────────
55
- {
56
- rule: 'NOSQL_INJECTION_WHERE',
57
- title: 'NoSQL Injection via $where',
58
- regex: /\$where\s*:/g,
59
- severity: 'high',
60
- cwe: 'CWE-943',
61
- owasp: 'A03:2021',
62
- description: '$where in MongoDB executes JavaScript and is vulnerable to injection. Use standard query operators.',
63
- fix: 'Replace $where with standard MongoDB operators ($eq, $gt, $regex, etc.)',
64
- },
65
- {
66
- rule: 'NOSQL_INJECTION_DYNAMIC',
67
- title: 'NoSQL Injection via Dynamic Query',
68
- regex: /\.find\(\s*(?:req\.|request\.|ctx\.)/g,
69
- severity: 'high',
70
- cwe: 'CWE-943',
71
- owasp: 'A03:2021',
72
- description: 'Passing request data directly to MongoDB find() enables NoSQL injection. Validate and whitelist query fields.',
73
- fix: 'Validate input: only allow expected fields, cast types explicitly',
74
- },
75
-
76
- // ── Command Injection ──────────────────────────────────────────────────────
77
- {
78
- rule: 'CMD_INJECTION_EXEC_TEMPLATE',
79
- title: 'Command Injection via exec() Template',
80
- regex: /\bexec(?:Sync)?\s*\(\s*`[^`]*\$\{/g,
81
- severity: 'critical',
82
- cwe: 'CWE-78',
83
- owasp: 'A03:2021',
84
- description: 'Shell command with interpolated values enables command injection. Use execFile() with argument arrays.',
85
- fix: 'Use execFile(cmd, [arg1, arg2]) instead of exec(`cmd ${arg}`)',
86
- },
87
- {
88
- rule: 'CMD_INJECTION_EXEC_CONCAT',
89
- title: 'Command Injection via exec() Concatenation',
90
- regex: /\bexec(?:Sync)?\s*\(\s*["'][^"']*["']\s*\+/g,
91
- severity: 'critical',
92
- cwe: 'CWE-78',
93
- owasp: 'A03:2021',
94
- description: 'Shell command built with string concatenation enables injection. Use execFile() with arrays.',
95
- fix: 'Use execFile(cmd, [arg1, arg2]) or spawn(cmd, args) without shell: true',
96
- },
97
- {
98
- rule: 'CMD_INJECTION_SHELL_TRUE',
99
- title: 'Command Injection via shell: true',
100
- regex: /\bspawn(?:Sync)?\s*\([^)]*\bshell\s*:\s*true/g,
101
- severity: 'high',
102
- cwe: 'CWE-78',
103
- owasp: 'A03:2021',
104
- description: 'shell: true in spawn enables shell expansion and command injection. Pass args as array without shell.',
105
- fix: 'Remove shell: true and pass arguments as an array',
106
- },
107
- {
108
- rule: 'CMD_INJECTION_PYTHON_OS',
109
- title: 'Command Injection via os.system/popen',
110
- regex: /\b(?:os\.system|os\.popen|subprocess\.call|subprocess\.Popen)\s*\([^)]*(?:f['"]|\.format\(|\s*\+\s*)/g,
111
- severity: 'critical',
112
- cwe: 'CWE-78',
113
- owasp: 'A03:2021',
114
- description: 'Shell command with string formatting enables injection. Use subprocess.run() with args list.',
115
- fix: 'Use subprocess.run([cmd, arg1, arg2], shell=False)',
116
- },
117
-
118
- // ── Code Injection ─────────────────────────────────────────────────────────
119
- {
120
- rule: 'CODE_INJECTION_EVAL',
121
- title: 'Code Injection via eval()',
122
- regex: /\beval\s*\(\s*(?:req\.|request\.|ctx\.|params|query|body|input|data|user)/g,
123
- severity: 'critical',
124
- cwe: 'CWE-94',
125
- owasp: 'A03:2021',
126
- description: 'eval() with user input executes arbitrary code. Never pass user data to eval.',
127
- fix: 'Use JSON.parse() for data, a sandboxed interpreter, or restructure to avoid eval',
128
- },
129
- {
130
- rule: 'CODE_INJECTION_EVAL_GENERIC',
131
- title: 'Code Injection: eval() Usage',
132
- regex: /\beval\s*\(/g,
133
- severity: 'high',
134
- cwe: 'CWE-94',
135
- owasp: 'A03:2021',
136
- confidence: 'medium',
137
- description: 'eval() executes arbitrary code. Replace with JSON.parse(), Function, or a safer alternative.',
138
- fix: 'Replace eval() with JSON.parse() or a domain-specific parser',
139
- },
140
- {
141
- rule: 'CODE_INJECTION_NEW_FUNCTION',
142
- title: 'Code Injection via new Function()',
143
- regex: /\bnew\s+Function\s*\(/g,
144
- severity: 'high',
145
- cwe: 'CWE-94',
146
- owasp: 'A03:2021',
147
- description: 'new Function() is equivalent to eval(). Avoid dynamic code generation.',
148
- fix: 'Refactor to avoid dynamic code generation',
149
- },
150
- {
151
- rule: 'CODE_INJECTION_VM',
152
- title: 'Code Injection via vm.runInNewContext()',
153
- regex: /\bvm\.(?:runInNewContext|runInThisContext|compileFunction)\s*\(/g,
154
- severity: 'high',
155
- cwe: 'CWE-94',
156
- owasp: 'A03:2021',
157
- description: 'Node.js vm module does not provide security isolation. Use vm2 or isolated-vm for untrusted code.',
158
- fix: 'Use isolated-vm or a proper sandbox for untrusted code execution',
159
- },
160
-
161
- // ── XSS ────────────────────────────────────────────────────────────────────
162
- {
163
- rule: 'XSS_DANGEROUS_HTML',
164
- title: 'XSS via dangerouslySetInnerHTML',
165
- regex: /dangerouslySetInnerHTML\s*=\s*\{\s*\{/g,
166
- severity: 'high',
167
- cwe: 'CWE-79',
168
- owasp: 'A03:2021',
169
- description: 'dangerouslySetInnerHTML can introduce XSS if the value contains user input.',
170
- fix: 'Sanitize with DOMPurify: dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(html)}}',
171
- },
172
- {
173
- rule: 'XSS_INNERHTML',
174
- title: 'XSS via innerHTML Assignment',
175
- regex: /\.innerHTML\s*=\s*(?!['"]<)/g,
176
- severity: 'high',
177
- cwe: 'CWE-79',
178
- owasp: 'A03:2021',
179
- description: 'innerHTML with dynamic data leads to XSS. Use textContent or DOMPurify.',
180
- fix: 'Use element.textContent for text, or DOMPurify.sanitize() for HTML',
181
- },
182
- {
183
- rule: 'XSS_DOCUMENT_WRITE',
184
- title: 'XSS via document.write()',
185
- regex: /\bdocument\.write(?:ln)?\s*\(/g,
186
- severity: 'medium',
187
- cwe: 'CWE-79',
188
- owasp: 'A03:2021',
189
- description: 'document.write() is deprecated and can introduce XSS. Use DOM manipulation.',
190
- fix: 'Use createElement/appendChild or textContent instead',
191
- },
192
- {
193
- rule: 'XSS_OUTERHTML',
194
- title: 'XSS via outerHTML Assignment',
195
- regex: /\.outerHTML\s*=/g,
196
- severity: 'high',
197
- cwe: 'CWE-79',
198
- owasp: 'A03:2021',
199
- description: 'outerHTML with dynamic content enables XSS. Sanitize with DOMPurify.',
200
- fix: 'Sanitize HTML with DOMPurify before assigning to outerHTML',
201
- },
202
- {
203
- rule: 'XSS_JQUERY_HTML',
204
- title: 'XSS via jQuery .html()',
205
- regex: /\$\([^)]+\)\.html\s*\(\s*(?!['"])/g,
206
- severity: 'high',
207
- cwe: 'CWE-79',
208
- owasp: 'A03:2021',
209
- description: 'jQuery .html() with dynamic data enables XSS. Use .text() or sanitize.',
210
- fix: 'Use .text() for plain text or sanitize HTML with DOMPurify before .html()',
211
- },
212
- {
213
- rule: 'XSS_V_HTML',
214
- title: 'XSS via Vue v-html Directive',
215
- regex: /v-html\s*=\s*["']/g,
216
- severity: 'high',
217
- cwe: 'CWE-79',
218
- owasp: 'A03:2021',
219
- description: 'Vue v-html renders raw HTML and is vulnerable to XSS. Sanitize before rendering.',
220
- fix: 'Sanitize with DOMPurify or use v-text for plain text',
221
- },
222
-
223
- // ── Path Traversal ─────────────────────────────────────────────────────────
224
- {
225
- rule: 'PATH_TRAVERSAL_FS',
226
- title: 'Path Traversal in File Operations',
227
- regex: /(?:readFile|readFileSync|createReadStream|writeFile|writeFileSync|unlink|unlinkSync|stat|statSync)\s*\(\s*(?:req\.|request\.|ctx\.|params|query|`[^`]*\$\{)/g,
228
- severity: 'critical',
229
- cwe: 'CWE-22',
230
- owasp: 'A01:2021',
231
- description: 'User input in file path enables directory traversal (../../etc/passwd). Validate and restrict paths.',
232
- fix: 'Use path.resolve() + validate that resolved path starts with allowed directory',
233
- },
234
- {
235
- rule: 'PATH_TRAVERSAL_DOTDOT',
236
- title: 'Path Traversal: No ../ Validation',
237
- regex: /path\.join\s*\([^)]*(?:req\.|request\.|ctx\.|params|query|body)/g,
238
- severity: 'high',
239
- cwe: 'CWE-22',
240
- owasp: 'A01:2021',
241
- description: 'path.join() with user input without ../​ validation enables traversal.',
242
- fix: 'After path.join, verify: if (!resolvedPath.startsWith(allowedDir)) throw new Error()',
243
- },
244
-
245
- // ── Template Injection ─────────────────────────────────────────────────────
246
- {
247
- rule: 'TEMPLATE_INJECTION_EJS',
248
- title: 'Server-Side Template Injection (EJS)',
249
- regex: /ejs\.render\s*\(\s*(?:req\.|request\.|ctx\.|body|query|params)/g,
250
- severity: 'critical',
251
- cwe: 'CWE-94',
252
- owasp: 'A03:2021',
253
- description: 'Passing user input as an EJS template enables server-side template injection (SSTI).',
254
- fix: 'Render from template files, pass user data only as template variables',
255
- },
256
- {
257
- rule: 'TEMPLATE_INJECTION_UNESCAPED',
258
- title: 'Unescaped Template Output',
259
- regex: /<%[-=]?\s*(?:req\.|request\.|body|query|params)/g,
260
- severity: 'high',
261
- cwe: 'CWE-79',
262
- owasp: 'A03:2021',
263
- description: 'Unescaped template output with user data enables XSS. Use escaped output.',
264
- fix: 'Use <%- sanitize(userInput) %> or escape before rendering',
265
- },
266
-
267
- // ── Header Injection ───────────────────────────────────────────────────────
268
- {
269
- rule: 'HEADER_INJECTION',
270
- title: 'HTTP Header Injection',
271
- regex: /(?:setHeader|writeHead|header)\s*\([^,]*,\s*(?:req\.|request\.|ctx\.|body|query|params)/g,
272
- severity: 'high',
273
- cwe: 'CWE-113',
274
- owasp: 'A03:2021',
275
- description: 'User input in HTTP headers enables header injection / response splitting.',
276
- fix: 'Validate and sanitize: strip newlines (\\r\\n) from header values',
277
- },
278
-
279
- // ── Open Redirect ──────────────────────────────────────────────────────────
280
- {
281
- rule: 'OPEN_REDIRECT',
282
- title: 'Open Redirect',
283
- regex: /(?:res\.redirect|redirect|location\.href|window\.location)\s*(?:\(|=)\s*(?:req\.|request\.|ctx\.|query|params)/g,
284
- severity: 'medium',
285
- cwe: 'CWE-601',
286
- owasp: 'A01:2021',
287
- description: 'Redirecting to user-supplied URL enables phishing via open redirect.',
288
- fix: 'Validate redirect URL is relative or matches an allowlist of trusted domains',
289
- },
290
-
291
- // ── Log Injection ──────────────────────────────────────────────────────────
292
- {
293
- rule: 'LOG_INJECTION',
294
- title: 'Log Injection',
295
- regex: /(?:console\.log|logger\.\w+|log\.\w+)\s*\(\s*`[^`]*\$\{(?:req\.|request\.|ctx\.|body|query|params)/g,
296
- severity: 'medium',
297
- cwe: 'CWE-117',
298
- owasp: 'A09:2021',
299
- description: 'Unsanitized user input in logs enables log forging and injection attacks.',
300
- fix: 'Sanitize user input before logging: strip control characters and newlines',
301
- },
302
-
303
- // ── Regex DoS ──────────────────────────────────────────────────────────────
304
- {
305
- rule: 'REDOS',
306
- title: 'Regular Expression DoS (ReDoS)',
307
- regex: /new\s+RegExp\s*\(\s*(?:req\.|request\.|ctx\.|body|query|params|input|user)/g,
308
- severity: 'high',
309
- cwe: 'CWE-1333',
310
- owasp: 'A03:2021',
311
- description: 'User-controlled regex can cause catastrophic backtracking (ReDoS). Validate or use RE2.',
312
- fix: 'Use the re2 package for user-supplied patterns, or validate regex complexity',
313
- },
314
- {
315
- rule: 'REDOS_NESTED_QUANTIFIER',
316
- title: 'ReDoS: Nested Quantifiers in Regex',
317
- regex: /\/[^/]*\([^)]*[+*][^)]*\)[+*][^/]*\//g,
318
- severity: 'high',
319
- cwe: 'CWE-1333',
320
- owasp: 'A03:2021',
321
- description: 'Regex with nested quantifiers like (a+)+ or (\\w+)* causes catastrophic backtracking.',
322
- fix: 'Rewrite to avoid nested repetition or use a non-backtracking engine (re2 package).',
323
- },
324
- {
325
- rule: 'REDOS_DOT_STAR_LOOKAHEAD',
326
- title: 'ReDoS: .* with Lookahead',
327
- regex: /\/[^/]*\.\*[^/]*\(\?[!=][^/]*\//g,
328
- severity: 'medium',
329
- cwe: 'CWE-1333',
330
- owasp: 'A03:2021',
331
- description: 'Regex with .* followed by lookahead can cause catastrophic backtracking on non-matching input.',
332
- fix: 'Replace .* with a bounded class like [^\\n]{0,N} or use a non-backtracking engine (re2).',
333
- },
334
-
335
- // ── Command Injection with Secrets ────────────────────────────────────────
336
- {
337
- rule: 'CMD_INJECTION_SECRET_INTERPOLATION',
338
- title: 'Command Injection: Secret in Shell Command',
339
- regex: /\bexec(?:Sync)?\s*\(\s*`[^`]*\$\{[^}]*(?:secret|password|token|apiKey|api_key|credential)[^}]*\}/gi,
340
- severity: 'critical',
341
- cwe: 'CWE-78',
342
- owasp: 'A03:2021',
343
- description: 'Secret or credential interpolated into shell command. Both a command injection and credential exposure risk.',
344
- fix: 'Use execFileSync(cmd, [args]) with argument arrays. Never interpolate secrets into shell strings.',
345
- },
346
-
347
- // ── Python-specific Injection ─────────────────────────────────────────────
348
- {
349
- rule: 'PYTHON_SQL_FSTRING',
350
- title: 'SQL Injection via Python f-string',
351
- regex: /f["'](?:SELECT|INSERT|UPDATE|DELETE)\s+[^"']*\{/gi,
352
- severity: 'critical',
353
- cwe: 'CWE-89',
354
- owasp: 'A03:2021',
355
- description: 'Python f-string used in SQL query enables SQL injection. Use parameterized queries.',
356
- fix: 'Use cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))',
357
- },
358
- {
359
- rule: 'PYTHON_SUBPROCESS_SHELL',
360
- title: 'Command Injection via subprocess shell=True',
361
- regex: /subprocess\.(?:run|call|Popen)\s*\([^)]*shell\s*=\s*True/g,
362
- severity: 'high',
363
- cwe: 'CWE-78',
364
- owasp: 'A03:2021',
365
- description: 'subprocess with shell=True enables command injection when using user input.',
366
- fix: 'Use subprocess.run([cmd, arg1, arg2], shell=False)',
367
- },
368
-
369
- // ── Prototype Pollution ────────────────────────────────────────────────────
370
- {
371
- rule: 'PROTOTYPE_POLLUTION',
372
- title: 'Prototype Pollution',
373
- regex: /(?:Object\.assign|_\.merge|_\.extend|_\.defaultsDeep|lodash\.merge)\s*\(\s*(?:\{\}|[a-zA-Z]+),\s*(?:req\.|request\.|ctx\.|body|query|params|input|data)/g,
374
- severity: 'high',
375
- cwe: 'CWE-1321',
376
- owasp: 'A03:2021',
377
- description: 'Merging user input into objects can pollute Object.prototype. Validate input keys.',
378
- fix: 'Validate keys against an allowlist, or use Object.create(null) as target',
379
- },
380
-
381
- // ── XXE ────────────────────────────────────────────────────────────────────
382
- {
383
- rule: 'XXE_PARSER',
384
- title: 'XML External Entity (XXE) Injection',
385
- regex: /(?:xml2js|libxmljs|DOMParser|parseString|parseXML)\s*(?:\.\w+\s*)?\(/g,
386
- severity: 'high',
387
- cwe: 'CWE-611',
388
- owasp: 'A05:2017',
389
- confidence: 'medium',
390
- description: 'XML parsers with default settings may be vulnerable to XXE. Disable external entity processing.',
391
- fix: 'Disable DTDs and external entities in parser configuration',
392
- },
393
-
394
- // ── Insecure Deserialization ────────────────────────────────────────────────
395
- {
396
- rule: 'UNSAFE_DESERIALIZE_PICKLE',
397
- title: 'Unsafe Deserialization: pickle',
398
- regex: /\bpickle\.loads?\s*\(/g,
399
- severity: 'critical',
400
- cwe: 'CWE-502',
401
- owasp: 'A08:2021',
402
- description: 'pickle.loads() on untrusted data enables arbitrary code execution.',
403
- fix: 'Use JSON, msgpack, or protobuf for untrusted data serialization',
404
- },
405
- {
406
- rule: 'UNSAFE_DESERIALIZE_YAML',
407
- title: 'Unsafe Deserialization: yaml.load()',
408
- regex: /\byaml\.load\s*\(\s*(?!.*Loader\s*=\s*yaml\.SafeLoader)/g,
409
- severity: 'high',
410
- cwe: 'CWE-502',
411
- owasp: 'A08:2021',
412
- description: 'yaml.load() without SafeLoader can execute arbitrary Python code.',
413
- fix: 'Use yaml.safe_load() or yaml.load(data, Loader=yaml.SafeLoader)',
414
- },
415
- {
416
- rule: 'UNSAFE_DESERIALIZE_UNSERIALIZE',
417
- title: 'Unsafe Deserialization: PHP unserialize()',
418
- regex: /\bunserialize\s*\(\s*\$/g,
419
- severity: 'critical',
420
- cwe: 'CWE-502',
421
- owasp: 'A08:2021',
422
- description: 'PHP unserialize() with user input enables object injection attacks.',
423
- fix: 'Use json_decode() instead, or validate input with allowed_classes option',
424
- },
425
-
426
- // ── Vibe Code Detection (AI-generated code with security gaps) ──────────
427
- {
428
- rule: 'VIBE_TODO_AUTH',
429
- title: 'Vibe Code: TODO to Add Authentication',
430
- regex: /(?:\/\/|#|\/\*)\s*(?:TODO|FIXME|HACK|XXX)\s*:?\s*(?:add|implement|fix|handle)\s*(?:auth|authentication|authorization|permission|access.?control|login|session)/gi,
431
- severity: 'high',
432
- cwe: 'CWE-306',
433
- owasp: 'A07:2021',
434
- confidence: 'high',
435
- description: 'TODO comment indicates missing authentication/authorization. Common in AI-generated code that creates endpoints without security.',
436
- fix: 'Implement the missing authentication before shipping. Do not leave security TODOs in production code.',
437
- },
438
- {
439
- rule: 'VIBE_TODO_VALIDATION',
440
- title: 'Vibe Code: TODO to Add Input Validation',
441
- regex: /(?:\/\/|#|\/\*)\s*(?:TODO|FIXME|HACK|XXX)\s*:?\s*(?:add|implement|fix|handle)\s*(?:valid|sanitiz|escap|filter|check.?input|input.?valid)/gi,
442
- severity: 'medium',
443
- cwe: 'CWE-20',
444
- owasp: 'A03:2021',
445
- confidence: 'high',
446
- description: 'TODO comment indicates missing input validation. AI-generated code often creates the happy path without validation.',
447
- fix: 'Implement input validation before shipping. Add schema validation (Zod, Joi) for all user inputs.',
448
- },
449
- {
450
- rule: 'VIBE_PLACEHOLDER_SECRET',
451
- title: 'Vibe Code: Placeholder Secret Left in Code',
452
- regex: /(?:api[_-]?key|secret|password|token)\s*[:=]\s*['"](?:your[_-]?(?:api[_-]?)?key[_-]?here|sk[_-]xxx|changeme|password123|test123|replace[_-]?me|insert[_-]?here|placeholder|example|CHANGE_ME|YOUR_SECRET)['"]/gi,
453
- severity: 'high',
454
- cwe: 'CWE-798',
455
- owasp: 'A07:2021',
456
- description: 'Placeholder secret left in code. AI-generated code often includes example credentials that developers forget to replace.',
457
- fix: 'Replace with environment variable: process.env.API_KEY. Never commit placeholder secrets.',
458
- },
459
- {
460
- rule: 'VIBE_CRUD_NO_AUTH',
461
- title: 'Vibe Code: CRUD Endpoints Without Auth Middleware',
462
- regex: /(?:router|app)\.(?:post|put|patch|delete)\s*\(\s*['"]\/(?:api\/)?(?:users?|posts?|items?|products?|orders?|comments?|messages?)(?:\/:[^'"]*)?['"]\s*,\s*(?:async\s+)?\(\s*(?:req|request)/g,
463
- severity: 'high',
464
- cwe: 'CWE-862',
465
- owasp: 'A01:2021',
466
- confidence: 'medium',
467
- description: 'Mutation endpoint (POST/PUT/PATCH/DELETE) with no visible auth middleware. Common in AI-generated CRUD boilerplate.',
468
- fix: 'Add authentication middleware before the route handler: router.post("/api/users", authMiddleware, handler)',
469
- },
470
- ];
471
-
472
- // =============================================================================
473
- // INJECTION TESTER AGENT
474
- // =============================================================================
475
-
476
- export class InjectionTester extends BaseAgent {
477
- constructor() {
478
- super('InjectionTester', 'Detect injection vulnerabilities across all classes', 'injection');
479
- }
480
-
481
- async analyze(context) {
482
- const { rootPath, files } = context;
483
- const codeFiles = files.filter(f => {
484
- const ext = path.extname(f).toLowerCase();
485
- return ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
486
- '.py', '.rb', '.php', '.go', '.java'].includes(ext);
487
- });
488
-
489
- let findings = [];
490
-
491
- for (const file of codeFiles) {
492
- const fileFindings = this.scanFileWithPatterns(file, PATTERNS);
493
- findings = findings.concat(fileFindings);
494
- }
495
-
496
- return findings;
497
- }
498
- }
499
-
500
- export default InjectionTester;
1
+ /**
2
+ * InjectionTester Agent
3
+ * ======================
4
+ *
5
+ * Detects injection vulnerabilities by tracing data flow patterns
6
+ * from user input to dangerous sinks.
7
+ *
8
+ * Covers: SQL Injection, NoSQL Injection, Command Injection,
9
+ * Code Injection, XSS, LDAP Injection, Template Injection,
10
+ * Header Injection, Path Traversal, Log Injection,
11
+ * GraphQL Injection, Open Redirect.
12
+ */
13
+
14
+ import path from 'path';
15
+ import { BaseAgent, createFinding } from './base-agent.js';
16
+
17
+ // =============================================================================
18
+ // INJECTION PATTERNS
19
+ // =============================================================================
20
+
21
+ const PATTERNS = [
22
+ // ── SQL Injection ──────────────────────────────────────────────────────────
23
+ {
24
+ rule: 'SQL_INJECTION_TEMPLATE_LITERAL',
25
+ title: 'SQL Injection via Template Literal',
26
+ regex: /`(?:SELECT|INSERT|UPDATE|DELETE|DROP\s+TABLE|ALTER\s+TABLE|TRUNCATE|CREATE|REPLACE|MERGE)[^`]*\$\{/gi,
27
+ severity: 'critical',
28
+ cwe: 'CWE-89',
29
+ owasp: 'A03:2021',
30
+ description: 'SQL query with interpolated template variable. Use parameterized queries ($1, ?) or an ORM.',
31
+ fix: 'Use parameterized queries: db.query("SELECT * FROM users WHERE id = $1", [userId])',
32
+ },
33
+ {
34
+ rule: 'SQL_INJECTION_CONCAT',
35
+ title: 'SQL Injection via String Concatenation',
36
+ regex: /["'](?:SELECT|INSERT|UPDATE|DELETE)\s+[^"']{4,}["']\s*\+/gi,
37
+ severity: 'high',
38
+ cwe: 'CWE-89',
39
+ owasp: 'A03:2021',
40
+ description: 'SQL built with string concatenation is vulnerable to injection. Use parameterized queries.',
41
+ fix: 'Replace string concat with parameterized query or ORM method',
42
+ },
43
+ {
44
+ rule: 'SQL_INJECTION_RAW',
45
+ title: 'Raw SQL Query (Prisma/Sequelize/Knex)',
46
+ regex: /(?:\$queryRaw|\.raw|knex\.raw)\s*\(\s*`[^`]*\$\{/gi,
47
+ severity: 'critical',
48
+ cwe: 'CWE-89',
49
+ owasp: 'A03:2021',
50
+ description: 'ORM raw query with interpolated values bypasses parameterization. Use tagged templates or bind parameters.',
51
+ fix: 'Prisma: use $queryRaw`...${Prisma.sql}...`; Sequelize: use bind parameters',
52
+ },
53
+
54
+ // ── NoSQL Injection ────────────────────────────────────────────────────────
55
+ {
56
+ rule: 'NOSQL_INJECTION_WHERE',
57
+ title: 'NoSQL Injection via $where',
58
+ regex: /\$where\s*:/g,
59
+ severity: 'high',
60
+ cwe: 'CWE-943',
61
+ owasp: 'A03:2021',
62
+ description: '$where in MongoDB executes JavaScript and is vulnerable to injection. Use standard query operators.',
63
+ fix: 'Replace $where with standard MongoDB operators ($eq, $gt, $regex, etc.)',
64
+ },
65
+ {
66
+ rule: 'NOSQL_INJECTION_DYNAMIC',
67
+ title: 'NoSQL Injection via Dynamic Query',
68
+ regex: /\.find\(\s*(?:req\.|request\.|ctx\.)/g,
69
+ severity: 'high',
70
+ cwe: 'CWE-943',
71
+ owasp: 'A03:2021',
72
+ description: 'Passing request data directly to MongoDB find() enables NoSQL injection. Validate and whitelist query fields.',
73
+ fix: 'Validate input: only allow expected fields, cast types explicitly',
74
+ },
75
+
76
+ // ── Command Injection ──────────────────────────────────────────────────────
77
+ {
78
+ rule: 'CMD_INJECTION_EXEC_TEMPLATE',
79
+ title: 'Command Injection via exec() Template',
80
+ regex: /\bexec(?:Sync)?\s*\(\s*`[^`]*\$\{/g,
81
+ severity: 'critical',
82
+ cwe: 'CWE-78',
83
+ owasp: 'A03:2021',
84
+ description: 'Shell command with interpolated values enables command injection. Use execFile() with argument arrays.',
85
+ fix: 'Use execFile(cmd, [arg1, arg2]) instead of exec(`cmd ${arg}`)',
86
+ },
87
+ {
88
+ rule: 'CMD_INJECTION_EXEC_CONCAT',
89
+ title: 'Command Injection via exec() Concatenation',
90
+ regex: /\bexec(?:Sync)?\s*\(\s*["'][^"']*["']\s*\+/g,
91
+ severity: 'critical',
92
+ cwe: 'CWE-78',
93
+ owasp: 'A03:2021',
94
+ description: 'Shell command built with string concatenation enables injection. Use execFile() with arrays.',
95
+ fix: 'Use execFile(cmd, [arg1, arg2]) or spawn(cmd, args) without shell: true',
96
+ },
97
+ {
98
+ rule: 'CMD_INJECTION_SHELL_TRUE',
99
+ title: 'Command Injection via shell: true',
100
+ regex: /\bspawn(?:Sync)?\s*\([^)]*\bshell\s*:\s*true/g,
101
+ severity: 'high',
102
+ cwe: 'CWE-78',
103
+ owasp: 'A03:2021',
104
+ description: 'shell: true in spawn enables shell expansion and command injection. Pass args as array without shell.',
105
+ fix: 'Remove shell: true and pass arguments as an array',
106
+ },
107
+ {
108
+ rule: 'CMD_INJECTION_PYTHON_OS',
109
+ title: 'Command Injection via os.system/popen',
110
+ regex: /\b(?:os\.system|os\.popen|subprocess\.call|subprocess\.Popen)\s*\([^)]*(?:f['"]|\.format\(|\s*\+\s*)/g,
111
+ severity: 'critical',
112
+ cwe: 'CWE-78',
113
+ owasp: 'A03:2021',
114
+ description: 'Shell command with string formatting enables injection. Use subprocess.run() with args list.',
115
+ fix: 'Use subprocess.run([cmd, arg1, arg2], shell=False)',
116
+ },
117
+
118
+ // ── Code Injection ─────────────────────────────────────────────────────────
119
+ {
120
+ rule: 'CODE_INJECTION_EVAL',
121
+ title: 'Code Injection via eval()',
122
+ regex: /\beval\s*\(\s*(?:req\.|request\.|ctx\.|params|query|body|input|data|user)/g,
123
+ severity: 'critical',
124
+ cwe: 'CWE-94',
125
+ owasp: 'A03:2021',
126
+ description: 'eval() with user input executes arbitrary code. Never pass user data to eval.',
127
+ fix: 'Use JSON.parse() for data, a sandboxed interpreter, or restructure to avoid eval',
128
+ },
129
+ {
130
+ rule: 'CODE_INJECTION_EVAL_GENERIC',
131
+ title: 'Code Injection: eval() Usage',
132
+ regex: /\beval\s*\(/g,
133
+ severity: 'high',
134
+ cwe: 'CWE-94',
135
+ owasp: 'A03:2021',
136
+ confidence: 'medium',
137
+ description: 'eval() executes arbitrary code. Replace with JSON.parse(), Function, or a safer alternative.',
138
+ fix: 'Replace eval() with JSON.parse() or a domain-specific parser',
139
+ },
140
+ {
141
+ rule: 'CODE_INJECTION_NEW_FUNCTION',
142
+ title: 'Code Injection via new Function()',
143
+ regex: /\bnew\s+Function\s*\(/g,
144
+ severity: 'high',
145
+ cwe: 'CWE-94',
146
+ owasp: 'A03:2021',
147
+ description: 'new Function() is equivalent to eval(). Avoid dynamic code generation.',
148
+ fix: 'Refactor to avoid dynamic code generation',
149
+ },
150
+ {
151
+ rule: 'CODE_INJECTION_VM',
152
+ title: 'Code Injection via vm.runInNewContext()',
153
+ regex: /\bvm\.(?:runInNewContext|runInThisContext|compileFunction)\s*\(/g,
154
+ severity: 'high',
155
+ cwe: 'CWE-94',
156
+ owasp: 'A03:2021',
157
+ description: 'Node.js vm module does not provide security isolation. Use vm2 or isolated-vm for untrusted code.',
158
+ fix: 'Use isolated-vm or a proper sandbox for untrusted code execution',
159
+ },
160
+
161
+ // ── XSS ────────────────────────────────────────────────────────────────────
162
+ {
163
+ rule: 'XSS_DANGEROUS_HTML',
164
+ title: 'XSS via dangerouslySetInnerHTML',
165
+ regex: /dangerouslySetInnerHTML\s*=\s*\{\s*\{/g,
166
+ severity: 'high',
167
+ cwe: 'CWE-79',
168
+ owasp: 'A03:2021',
169
+ description: 'dangerouslySetInnerHTML can introduce XSS if the value contains user input.',
170
+ fix: 'Sanitize with DOMPurify: dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(html)}}',
171
+ },
172
+ {
173
+ rule: 'XSS_INNERHTML',
174
+ title: 'XSS via innerHTML Assignment',
175
+ regex: /\.innerHTML\s*=\s*(?!['"]<)/g,
176
+ severity: 'high',
177
+ cwe: 'CWE-79',
178
+ owasp: 'A03:2021',
179
+ description: 'innerHTML with dynamic data leads to XSS. Use textContent or DOMPurify.',
180
+ fix: 'Use element.textContent for text, or DOMPurify.sanitize() for HTML',
181
+ },
182
+ {
183
+ rule: 'XSS_DOCUMENT_WRITE',
184
+ title: 'XSS via document.write()',
185
+ regex: /\bdocument\.write(?:ln)?\s*\(/g,
186
+ severity: 'medium',
187
+ cwe: 'CWE-79',
188
+ owasp: 'A03:2021',
189
+ description: 'document.write() is deprecated and can introduce XSS. Use DOM manipulation.',
190
+ fix: 'Use createElement/appendChild or textContent instead',
191
+ },
192
+ {
193
+ rule: 'XSS_OUTERHTML',
194
+ title: 'XSS via outerHTML Assignment',
195
+ regex: /\.outerHTML\s*=/g,
196
+ severity: 'high',
197
+ cwe: 'CWE-79',
198
+ owasp: 'A03:2021',
199
+ description: 'outerHTML with dynamic content enables XSS. Sanitize with DOMPurify.',
200
+ fix: 'Sanitize HTML with DOMPurify before assigning to outerHTML',
201
+ },
202
+ {
203
+ rule: 'XSS_JQUERY_HTML',
204
+ title: 'XSS via jQuery .html()',
205
+ regex: /\$\([^)]+\)\.html\s*\(\s*(?!['"])/g,
206
+ severity: 'high',
207
+ cwe: 'CWE-79',
208
+ owasp: 'A03:2021',
209
+ description: 'jQuery .html() with dynamic data enables XSS. Use .text() or sanitize.',
210
+ fix: 'Use .text() for plain text or sanitize HTML with DOMPurify before .html()',
211
+ },
212
+ {
213
+ rule: 'XSS_V_HTML',
214
+ title: 'XSS via Vue v-html Directive',
215
+ regex: /v-html\s*=\s*["']/g,
216
+ severity: 'high',
217
+ cwe: 'CWE-79',
218
+ owasp: 'A03:2021',
219
+ description: 'Vue v-html renders raw HTML and is vulnerable to XSS. Sanitize before rendering.',
220
+ fix: 'Sanitize with DOMPurify or use v-text for plain text',
221
+ },
222
+
223
+ // ── Path Traversal ─────────────────────────────────────────────────────────
224
+ {
225
+ rule: 'PATH_TRAVERSAL_FS',
226
+ title: 'Path Traversal in File Operations',
227
+ regex: /(?:readFile|readFileSync|createReadStream|writeFile|writeFileSync|unlink|unlinkSync|stat|statSync)\s*\(\s*(?:req\.|request\.|ctx\.|params|query|`[^`]*\$\{)/g,
228
+ severity: 'critical',
229
+ cwe: 'CWE-22',
230
+ owasp: 'A01:2021',
231
+ description: 'User input in file path enables directory traversal (../../etc/passwd). Validate and restrict paths.',
232
+ fix: 'Use path.resolve() + validate that resolved path starts with allowed directory',
233
+ },
234
+ {
235
+ rule: 'PATH_TRAVERSAL_DOTDOT',
236
+ title: 'Path Traversal: No ../ Validation',
237
+ regex: /path\.join\s*\([^)]*(?:req\.|request\.|ctx\.|params|query|body)/g,
238
+ severity: 'high',
239
+ cwe: 'CWE-22',
240
+ owasp: 'A01:2021',
241
+ description: 'path.join() with user input without ../​ validation enables traversal.',
242
+ fix: 'After path.join, verify: if (!resolvedPath.startsWith(allowedDir)) throw new Error()',
243
+ },
244
+
245
+ // ── Template Injection ─────────────────────────────────────────────────────
246
+ {
247
+ rule: 'TEMPLATE_INJECTION_EJS',
248
+ title: 'Server-Side Template Injection (EJS)',
249
+ regex: /ejs\.render\s*\(\s*(?:req\.|request\.|ctx\.|body|query|params)/g,
250
+ severity: 'critical',
251
+ cwe: 'CWE-94',
252
+ owasp: 'A03:2021',
253
+ description: 'Passing user input as an EJS template enables server-side template injection (SSTI).',
254
+ fix: 'Render from template files, pass user data only as template variables',
255
+ },
256
+ {
257
+ rule: 'TEMPLATE_INJECTION_UNESCAPED',
258
+ title: 'Unescaped Template Output',
259
+ regex: /<%[-=]?\s*(?:req\.|request\.|body|query|params)/g,
260
+ severity: 'high',
261
+ cwe: 'CWE-79',
262
+ owasp: 'A03:2021',
263
+ description: 'Unescaped template output with user data enables XSS. Use escaped output.',
264
+ fix: 'Use <%- sanitize(userInput) %> or escape before rendering',
265
+ },
266
+
267
+ // ── Header Injection ───────────────────────────────────────────────────────
268
+ {
269
+ rule: 'HEADER_INJECTION',
270
+ title: 'HTTP Header Injection',
271
+ regex: /(?:setHeader|writeHead|header)\s*\([^,]*,\s*(?:req\.|request\.|ctx\.|body|query|params)/g,
272
+ severity: 'high',
273
+ cwe: 'CWE-113',
274
+ owasp: 'A03:2021',
275
+ description: 'User input in HTTP headers enables header injection / response splitting.',
276
+ fix: 'Validate and sanitize: strip newlines (\\r\\n) from header values',
277
+ },
278
+
279
+ // ── Open Redirect ──────────────────────────────────────────────────────────
280
+ {
281
+ rule: 'OPEN_REDIRECT',
282
+ title: 'Open Redirect',
283
+ regex: /(?:res\.redirect|redirect|location\.href|window\.location)\s*(?:\(|=)\s*(?:req\.|request\.|ctx\.|query|params)/g,
284
+ severity: 'medium',
285
+ cwe: 'CWE-601',
286
+ owasp: 'A01:2021',
287
+ description: 'Redirecting to user-supplied URL enables phishing via open redirect.',
288
+ fix: 'Validate redirect URL is relative or matches an allowlist of trusted domains',
289
+ },
290
+
291
+ // ── Log Injection ──────────────────────────────────────────────────────────
292
+ {
293
+ rule: 'LOG_INJECTION',
294
+ title: 'Log Injection',
295
+ regex: /(?:console\.log|logger\.\w+|log\.\w+)\s*\(\s*`[^`]*\$\{(?:req\.|request\.|ctx\.|body|query|params)/g,
296
+ severity: 'medium',
297
+ cwe: 'CWE-117',
298
+ owasp: 'A09:2021',
299
+ description: 'Unsanitized user input in logs enables log forging and injection attacks.',
300
+ fix: 'Sanitize user input before logging: strip control characters and newlines',
301
+ },
302
+
303
+ // ── Regex DoS ──────────────────────────────────────────────────────────────
304
+ {
305
+ rule: 'REDOS',
306
+ title: 'Regular Expression DoS (ReDoS)',
307
+ regex: /new\s+RegExp\s*\(\s*(?:req\.|request\.|ctx\.|body|query|params|input|user)/g,
308
+ severity: 'high',
309
+ cwe: 'CWE-1333',
310
+ owasp: 'A03:2021',
311
+ description: 'User-controlled regex can cause catastrophic backtracking (ReDoS). Validate or use RE2.',
312
+ fix: 'Use the re2 package for user-supplied patterns, or validate regex complexity',
313
+ },
314
+ {
315
+ rule: 'REDOS_NESTED_QUANTIFIER',
316
+ title: 'ReDoS: Nested Quantifiers in Regex',
317
+ regex: /\/[^/]*\([^)]*[+*][^)]*\)[+*][^/]*\//g,
318
+ severity: 'high',
319
+ cwe: 'CWE-1333',
320
+ owasp: 'A03:2021',
321
+ description: 'Regex with nested quantifiers like (a+)+ or (\\w+)* causes catastrophic backtracking.',
322
+ fix: 'Rewrite to avoid nested repetition or use a non-backtracking engine (re2 package).',
323
+ },
324
+ {
325
+ rule: 'REDOS_DOT_STAR_LOOKAHEAD',
326
+ title: 'ReDoS: .* with Lookahead',
327
+ regex: /\/[^/]*\.\*[^/]*\(\?[!=][^/]*\//g,
328
+ severity: 'medium',
329
+ cwe: 'CWE-1333',
330
+ owasp: 'A03:2021',
331
+ description: 'Regex with .* followed by lookahead can cause catastrophic backtracking on non-matching input.',
332
+ fix: 'Replace .* with a bounded class like [^\\n]{0,N} or use a non-backtracking engine (re2).',
333
+ },
334
+
335
+ // ── Command Injection with Secrets ────────────────────────────────────────
336
+ {
337
+ rule: 'CMD_INJECTION_SECRET_INTERPOLATION',
338
+ title: 'Command Injection: Secret in Shell Command',
339
+ regex: /\bexec(?:Sync)?\s*\(\s*`[^`]*\$\{[^}]*(?:secret|password|token|apiKey|api_key|credential)[^}]*\}/gi,
340
+ severity: 'critical',
341
+ cwe: 'CWE-78',
342
+ owasp: 'A03:2021',
343
+ description: 'Secret or credential interpolated into shell command. Both a command injection and credential exposure risk.',
344
+ fix: 'Use execFileSync(cmd, [args]) with argument arrays. Never interpolate secrets into shell strings.',
345
+ },
346
+
347
+ // ── Python-specific Injection ─────────────────────────────────────────────
348
+ {
349
+ rule: 'PYTHON_SQL_FSTRING',
350
+ title: 'SQL Injection via Python f-string',
351
+ regex: /f["'](?:SELECT|INSERT|UPDATE|DELETE)\s+[^"']*\{/gi,
352
+ severity: 'critical',
353
+ cwe: 'CWE-89',
354
+ owasp: 'A03:2021',
355
+ description: 'Python f-string used in SQL query enables SQL injection. Use parameterized queries.',
356
+ fix: 'Use cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))',
357
+ },
358
+ {
359
+ rule: 'PYTHON_SUBPROCESS_SHELL',
360
+ title: 'Command Injection via subprocess shell=True',
361
+ regex: /subprocess\.(?:run|call|Popen)\s*\([^)]*shell\s*=\s*True/g,
362
+ severity: 'high',
363
+ cwe: 'CWE-78',
364
+ owasp: 'A03:2021',
365
+ description: 'subprocess with shell=True enables command injection when using user input.',
366
+ fix: 'Use subprocess.run([cmd, arg1, arg2], shell=False)',
367
+ },
368
+
369
+ // ── Prototype Pollution ────────────────────────────────────────────────────
370
+ {
371
+ rule: 'PROTOTYPE_POLLUTION',
372
+ title: 'Prototype Pollution',
373
+ regex: /(?:Object\.assign|_\.merge|_\.extend|_\.defaultsDeep|lodash\.merge)\s*\(\s*(?:\{\}|[a-zA-Z]+),\s*(?:req\.|request\.|ctx\.|body|query|params|input|data)/g,
374
+ severity: 'high',
375
+ cwe: 'CWE-1321',
376
+ owasp: 'A03:2021',
377
+ description: 'Merging user input into objects can pollute Object.prototype. Validate input keys.',
378
+ fix: 'Validate keys against an allowlist, or use Object.create(null) as target',
379
+ },
380
+
381
+ // ── XXE ────────────────────────────────────────────────────────────────────
382
+ {
383
+ rule: 'XXE_PARSER',
384
+ title: 'XML External Entity (XXE) Injection',
385
+ regex: /(?:xml2js|libxmljs|DOMParser|parseString|parseXML)\s*(?:\.\w+\s*)?\(/g,
386
+ severity: 'high',
387
+ cwe: 'CWE-611',
388
+ owasp: 'A05:2017',
389
+ confidence: 'medium',
390
+ description: 'XML parsers with default settings may be vulnerable to XXE. Disable external entity processing.',
391
+ fix: 'Disable DTDs and external entities in parser configuration',
392
+ },
393
+
394
+ // ── Insecure Deserialization ────────────────────────────────────────────────
395
+ {
396
+ rule: 'UNSAFE_DESERIALIZE_PICKLE',
397
+ title: 'Unsafe Deserialization: pickle',
398
+ regex: /\bpickle\.loads?\s*\(/g,
399
+ severity: 'critical',
400
+ cwe: 'CWE-502',
401
+ owasp: 'A08:2021',
402
+ description: 'pickle.loads() on untrusted data enables arbitrary code execution.',
403
+ fix: 'Use JSON, msgpack, or protobuf for untrusted data serialization',
404
+ },
405
+ {
406
+ rule: 'UNSAFE_DESERIALIZE_YAML',
407
+ title: 'Unsafe Deserialization: yaml.load()',
408
+ regex: /\byaml\.load\s*\(\s*(?!.*Loader\s*=\s*yaml\.SafeLoader)/g,
409
+ severity: 'high',
410
+ cwe: 'CWE-502',
411
+ owasp: 'A08:2021',
412
+ description: 'yaml.load() without SafeLoader can execute arbitrary Python code.',
413
+ fix: 'Use yaml.safe_load() or yaml.load(data, Loader=yaml.SafeLoader)',
414
+ },
415
+ {
416
+ rule: 'UNSAFE_DESERIALIZE_UNSERIALIZE',
417
+ title: 'Unsafe Deserialization: PHP unserialize()',
418
+ regex: /\bunserialize\s*\(\s*\$/g,
419
+ severity: 'critical',
420
+ cwe: 'CWE-502',
421
+ owasp: 'A08:2021',
422
+ description: 'PHP unserialize() with user input enables object injection attacks.',
423
+ fix: 'Use json_decode() instead, or validate input with allowed_classes option',
424
+ },
425
+
426
+ // ── Vibe Code Detection (AI-generated code with security gaps) ──────────
427
+ {
428
+ rule: 'VIBE_TODO_AUTH',
429
+ title: 'Vibe Code: TODO to Add Authentication',
430
+ regex: /(?:\/\/|#|\/\*)\s*(?:TODO|FIXME|HACK|XXX)\s*:?\s*(?:add|implement|fix|handle)\s*(?:auth|authentication|authorization|permission|access.?control|login|session)/gi,
431
+ severity: 'high',
432
+ cwe: 'CWE-306',
433
+ owasp: 'A07:2021',
434
+ confidence: 'high',
435
+ description: 'TODO comment indicates missing authentication/authorization. Common in AI-generated code that creates endpoints without security.',
436
+ fix: 'Implement the missing authentication before shipping. Do not leave security TODOs in production code.',
437
+ },
438
+ {
439
+ rule: 'VIBE_TODO_VALIDATION',
440
+ title: 'Vibe Code: TODO to Add Input Validation',
441
+ regex: /(?:\/\/|#|\/\*)\s*(?:TODO|FIXME|HACK|XXX)\s*:?\s*(?:add|implement|fix|handle)\s*(?:valid|sanitiz|escap|filter|check.?input|input.?valid)/gi,
442
+ severity: 'medium',
443
+ cwe: 'CWE-20',
444
+ owasp: 'A03:2021',
445
+ confidence: 'high',
446
+ description: 'TODO comment indicates missing input validation. AI-generated code often creates the happy path without validation.',
447
+ fix: 'Implement input validation before shipping. Add schema validation (Zod, Joi) for all user inputs.',
448
+ },
449
+ {
450
+ rule: 'VIBE_PLACEHOLDER_SECRET',
451
+ title: 'Vibe Code: Placeholder Secret Left in Code',
452
+ regex: /(?:api[_-]?key|secret|password|token)\s*[:=]\s*['"](?:your[_-]?(?:api[_-]?)?key[_-]?here|sk[_-]xxx|changeme|password123|test123|replace[_-]?me|insert[_-]?here|placeholder|example|CHANGE_ME|YOUR_SECRET)['"]/gi,
453
+ severity: 'high',
454
+ cwe: 'CWE-798',
455
+ owasp: 'A07:2021',
456
+ description: 'Placeholder secret left in code. AI-generated code often includes example credentials that developers forget to replace.',
457
+ fix: 'Replace with environment variable: process.env.API_KEY. Never commit placeholder secrets.',
458
+ },
459
+ {
460
+ rule: 'VIBE_CRUD_NO_AUTH',
461
+ title: 'Vibe Code: CRUD Endpoints Without Auth Middleware',
462
+ regex: /(?:router|app)\.(?:post|put|patch|delete)\s*\(\s*['"]\/(?:api\/)?(?:users?|posts?|items?|products?|orders?|comments?|messages?)(?:\/:[^'"]*)?['"]\s*,\s*(?:async\s+)?\(\s*(?:req|request)/g,
463
+ severity: 'high',
464
+ cwe: 'CWE-862',
465
+ owasp: 'A01:2021',
466
+ confidence: 'medium',
467
+ description: 'Mutation endpoint (POST/PUT/PATCH/DELETE) with no visible auth middleware. Common in AI-generated CRUD boilerplate.',
468
+ fix: 'Add authentication middleware before the route handler: router.post("/api/users", authMiddleware, handler)',
469
+ },
470
+ ];
471
+
472
+ // =============================================================================
473
+ // INJECTION TESTER AGENT
474
+ // =============================================================================
475
+
476
+ export class InjectionTester extends BaseAgent {
477
+ constructor() {
478
+ super('InjectionTester', 'Detect injection vulnerabilities across all classes', 'injection');
479
+ }
480
+
481
+ async analyze(context) {
482
+ const { rootPath, files } = context;
483
+ const codeFiles = files.filter(f => {
484
+ const ext = path.extname(f).toLowerCase();
485
+ return ['.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs',
486
+ '.py', '.rb', '.php', '.go', '.java'].includes(ext);
487
+ });
488
+
489
+ let findings = [];
490
+
491
+ for (const file of codeFiles) {
492
+ const fileFindings = this.scanFileWithPatterns(file, PATTERNS);
493
+ findings = findings.concat(fileFindings);
494
+ }
495
+
496
+ return findings;
497
+ }
498
+ }
499
+
500
+ export default InjectionTester;