tryassay 0.33.1 → 0.33.2

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 (78) hide show
  1. package/dist/cli.js +2 -0
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/hunt.d.ts +2 -0
  4. package/dist/commands/hunt.js +58 -7
  5. package/dist/commands/hunt.js.map +1 -1
  6. package/dist/hunt/__tests__/finding-to-template.test.d.ts +1 -0
  7. package/dist/hunt/__tests__/finding-to-template.test.js +213 -0
  8. package/dist/hunt/__tests__/finding-to-template.test.js.map +1 -0
  9. package/dist/hunt/__tests__/parse-utils.test.js +28 -1
  10. package/dist/hunt/__tests__/parse-utils.test.js.map +1 -1
  11. package/dist/hunt/__tests__/taint-analysis.test.d.ts +1 -0
  12. package/dist/hunt/__tests__/taint-analysis.test.js +556 -0
  13. package/dist/hunt/__tests__/taint-analysis.test.js.map +1 -0
  14. package/dist/hunt/__tests__/templates.test.js +2 -2
  15. package/dist/hunt/__tests__/templates.test.js.map +1 -1
  16. package/dist/hunt/deep-dive.d.ts +2 -2
  17. package/dist/hunt/deep-dive.js +4 -4
  18. package/dist/hunt/deep-dive.js.map +1 -1
  19. package/dist/hunt/discovery.js +2 -2
  20. package/dist/hunt/discovery.js.map +1 -1
  21. package/dist/hunt/finding-to-template.d.ts +47 -0
  22. package/dist/hunt/finding-to-template.js +288 -0
  23. package/dist/hunt/finding-to-template.js.map +1 -0
  24. package/dist/hunt/orchestrator.d.ts +3 -0
  25. package/dist/hunt/orchestrator.js +20 -5
  26. package/dist/hunt/orchestrator.js.map +1 -1
  27. package/dist/hunt/taint-analysis.d.ts +49 -0
  28. package/dist/hunt/taint-analysis.js +429 -0
  29. package/dist/hunt/taint-analysis.js.map +1 -0
  30. package/dist/hunt/templates/csv-injection.d.ts +2 -0
  31. package/dist/hunt/templates/csv-injection.js +148 -0
  32. package/dist/hunt/templates/csv-injection.js.map +1 -0
  33. package/dist/hunt/templates/django-misconfig.d.ts +2 -0
  34. package/dist/hunt/templates/django-misconfig.js +172 -0
  35. package/dist/hunt/templates/django-misconfig.js.map +1 -0
  36. package/dist/hunt/templates/express-misconfig.d.ts +2 -0
  37. package/dist/hunt/templates/express-misconfig.js +156 -0
  38. package/dist/hunt/templates/express-misconfig.js.map +1 -0
  39. package/dist/hunt/templates/file-upload.d.ts +2 -0
  40. package/dist/hunt/templates/file-upload.js +131 -0
  41. package/dist/hunt/templates/file-upload.js.map +1 -0
  42. package/dist/hunt/templates/graphql-abuse.d.ts +2 -0
  43. package/dist/hunt/templates/graphql-abuse.js +161 -0
  44. package/dist/hunt/templates/graphql-abuse.js.map +1 -0
  45. package/dist/hunt/templates/hardcoded-credentials.d.ts +2 -0
  46. package/dist/hunt/templates/hardcoded-credentials.js +109 -0
  47. package/dist/hunt/templates/hardcoded-credentials.js.map +1 -0
  48. package/dist/hunt/templates/idor.d.ts +2 -0
  49. package/dist/hunt/templates/idor.js +102 -0
  50. package/dist/hunt/templates/idor.js.map +1 -0
  51. package/dist/hunt/templates/index.d.ts +2 -2
  52. package/dist/hunt/templates/index.js +38 -5
  53. package/dist/hunt/templates/index.js.map +1 -1
  54. package/dist/hunt/templates/insecure-deserialization.d.ts +2 -0
  55. package/dist/hunt/templates/insecure-deserialization.js +131 -0
  56. package/dist/hunt/templates/insecure-deserialization.js.map +1 -0
  57. package/dist/hunt/templates/mass-assignment.d.ts +2 -0
  58. package/dist/hunt/templates/mass-assignment.js +101 -0
  59. package/dist/hunt/templates/mass-assignment.js.map +1 -0
  60. package/dist/hunt/templates/nextjs-misconfig.d.ts +2 -0
  61. package/dist/hunt/templates/nextjs-misconfig.js +127 -0
  62. package/dist/hunt/templates/nextjs-misconfig.js.map +1 -0
  63. package/dist/hunt/templates/postmessage.d.ts +2 -0
  64. package/dist/hunt/templates/postmessage.js +180 -0
  65. package/dist/hunt/templates/postmessage.js.map +1 -0
  66. package/dist/hunt/templates/race-condition.d.ts +2 -0
  67. package/dist/hunt/templates/race-condition.js +138 -0
  68. package/dist/hunt/templates/race-condition.js.map +1 -0
  69. package/dist/hunt/templates/spring-misconfig.d.ts +2 -0
  70. package/dist/hunt/templates/spring-misconfig.js +177 -0
  71. package/dist/hunt/templates/spring-misconfig.js.map +1 -0
  72. package/dist/hunt/templates/xxe.d.ts +2 -0
  73. package/dist/hunt/templates/xxe.js +187 -0
  74. package/dist/hunt/templates/xxe.js.map +1 -0
  75. package/dist/hunt/triage.d.ts +2 -2
  76. package/dist/hunt/triage.js +4 -4
  77. package/dist/hunt/triage.js.map +1 -1
  78. package/package.json +1 -1
@@ -0,0 +1,556 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { buildImportGraph, findSources, findSinks, buildTaintContext, formatTaintContext, } from '../taint-analysis.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Helpers
5
+ // ---------------------------------------------------------------------------
6
+ const makeFile = (overrides) => ({
7
+ absolutePath: `/project/${overrides.relativePath}`,
8
+ content: '',
9
+ imports: [],
10
+ exports: [],
11
+ functions: [],
12
+ contentHash: 'hash',
13
+ isLowPriority: false,
14
+ ...overrides,
15
+ });
16
+ // ---------------------------------------------------------------------------
17
+ // buildImportGraph
18
+ // ---------------------------------------------------------------------------
19
+ describe('buildImportGraph', () => {
20
+ it('resolves relative imports between discovered files', () => {
21
+ const fileA = makeFile({
22
+ relativePath: 'src/routes.ts',
23
+ content: `import { query } from './db.js';`,
24
+ imports: ['./db.js'],
25
+ });
26
+ const fileB = makeFile({
27
+ relativePath: 'src/db.ts',
28
+ content: `export function query(sql: string) {}`,
29
+ exports: ['query'],
30
+ });
31
+ const edges = buildImportGraph([fileA, fileB]);
32
+ expect(edges).toHaveLength(1);
33
+ expect(edges[0].from).toBe('src/routes.ts');
34
+ expect(edges[0].to).toBe('src/db.ts');
35
+ expect(edges[0].symbols).toContain('query');
36
+ });
37
+ it('resolves imports without extension', () => {
38
+ const fileA = makeFile({
39
+ relativePath: 'src/handler.ts',
40
+ content: `import db from './db';`,
41
+ imports: ['./db'],
42
+ });
43
+ const fileB = makeFile({
44
+ relativePath: 'src/db.ts',
45
+ content: `export default pool;`,
46
+ exports: [],
47
+ });
48
+ const edges = buildImportGraph([fileA, fileB]);
49
+ expect(edges).toHaveLength(1);
50
+ expect(edges[0].to).toBe('src/db.ts');
51
+ expect(edges[0].symbols).toContain('db');
52
+ });
53
+ it('resolves parent-directory imports', () => {
54
+ const fileA = makeFile({
55
+ relativePath: 'src/routes/api.ts',
56
+ content: `import { pool } from '../db.js';`,
57
+ imports: ['../db.js'],
58
+ });
59
+ const fileB = makeFile({
60
+ relativePath: 'src/db.ts',
61
+ content: `export const pool = {};`,
62
+ exports: ['pool'],
63
+ });
64
+ const edges = buildImportGraph([fileA, fileB]);
65
+ expect(edges).toHaveLength(1);
66
+ expect(edges[0].from).toBe('src/routes/api.ts');
67
+ expect(edges[0].to).toBe('src/db.ts');
68
+ });
69
+ it('returns empty array when no imports resolve', () => {
70
+ const fileA = makeFile({
71
+ relativePath: 'src/app.ts',
72
+ content: `import express from 'express';`,
73
+ imports: ['express'],
74
+ });
75
+ const edges = buildImportGraph([fileA]);
76
+ expect(edges).toHaveLength(0);
77
+ });
78
+ it('extracts named, default, and namespace import symbols', () => {
79
+ const fileA = makeFile({
80
+ relativePath: 'src/app.ts',
81
+ content: `import { foo, bar as baz } from './utils.js';\nimport * as helpers from './utils.js';`,
82
+ imports: ['./utils.js'],
83
+ });
84
+ const fileB = makeFile({
85
+ relativePath: 'src/utils.ts',
86
+ content: `export function foo() {} export function bar() {}`,
87
+ exports: ['foo', 'bar'],
88
+ });
89
+ const edges = buildImportGraph([fileA, fileB]);
90
+ expect(edges).toHaveLength(1);
91
+ expect(edges[0].symbols).toContain('foo');
92
+ expect(edges[0].symbols).toContain('baz'); // renamed
93
+ expect(edges[0].symbols).toContain('helpers'); // namespace
94
+ });
95
+ it('handles require() style imports', () => {
96
+ const fileA = makeFile({
97
+ relativePath: 'src/app.js',
98
+ content: `const { query } = require('./db');`,
99
+ imports: ['./db'],
100
+ });
101
+ const fileB = makeFile({
102
+ relativePath: 'src/db.js',
103
+ content: `module.exports = { query };`,
104
+ exports: [],
105
+ });
106
+ const edges = buildImportGraph([fileA, fileB]);
107
+ expect(edges).toHaveLength(1);
108
+ expect(edges[0].symbols).toContain('query');
109
+ });
110
+ });
111
+ // ---------------------------------------------------------------------------
112
+ // findSources
113
+ // ---------------------------------------------------------------------------
114
+ describe('findSources', () => {
115
+ it('detects Express request sources', () => {
116
+ const file = makeFile({
117
+ relativePath: 'src/routes.ts',
118
+ content: `
119
+ app.get('/user/:id', (req, res) => {
120
+ const id = req.params.id;
121
+ const q = req.query.search;
122
+ const data = req.body;
123
+ });`,
124
+ });
125
+ const sources = findSources([file]);
126
+ expect(sources.length).toBeGreaterThanOrEqual(3);
127
+ const types = sources.map(s => s.type);
128
+ expect(types).toContain('request-param');
129
+ expect(types).toContain('query-string');
130
+ expect(types).toContain('request-body');
131
+ });
132
+ it('detects Koa context sources', () => {
133
+ const file = makeFile({
134
+ relativePath: 'src/koa-handler.ts',
135
+ content: `
136
+ router.get('/item', async (ctx) => {
137
+ const q = ctx.query;
138
+ const params = ctx.params;
139
+ const body = ctx.request.body;
140
+ });`,
141
+ });
142
+ const sources = findSources([file]);
143
+ expect(sources.length).toBeGreaterThanOrEqual(3);
144
+ });
145
+ it('detects Lambda event sources', () => {
146
+ const file = makeFile({
147
+ relativePath: 'src/lambda.ts',
148
+ content: `
149
+ export const handler = async (event) => {
150
+ const body = event.body;
151
+ const params = event.queryStringParameters;
152
+ };`,
153
+ });
154
+ const sources = findSources([file]);
155
+ expect(sources.length).toBeGreaterThanOrEqual(2);
156
+ const types = sources.map(s => s.type);
157
+ expect(types).toContain('request-body');
158
+ expect(types).toContain('query-string');
159
+ });
160
+ it('detects React Router hooks', () => {
161
+ const file = makeFile({
162
+ relativePath: 'src/page.tsx',
163
+ content: `
164
+ const params = useParams();
165
+ const [searchParams] = useSearchParams();`,
166
+ });
167
+ const sources = findSources([file]);
168
+ expect(sources.length).toBeGreaterThanOrEqual(2);
169
+ const types = sources.map(s => s.type);
170
+ expect(types).toContain('url-param');
171
+ expect(types).toContain('query-string');
172
+ });
173
+ it('detects Python Flask sources', () => {
174
+ const file = makeFile({
175
+ relativePath: 'app/views.py',
176
+ content: `
177
+ def index():
178
+ name = request.args.get('name')
179
+ data = request.form['email']
180
+ payload = request.json`,
181
+ });
182
+ const sources = findSources([file]);
183
+ expect(sources.length).toBeGreaterThanOrEqual(3);
184
+ });
185
+ it('detects Java annotation sources', () => {
186
+ const file = makeFile({
187
+ relativePath: 'src/Controller.java',
188
+ content: `
189
+ @GetMapping("/user")
190
+ public User getUser(@RequestParam String name, @PathVariable Long id, @RequestBody UserDto dto) {
191
+ return userService.find(name, id);
192
+ }`,
193
+ });
194
+ const sources = findSources([file]);
195
+ expect(sources.length).toBeGreaterThanOrEqual(3);
196
+ const types = sources.map(s => s.type);
197
+ expect(types).toContain('request-param');
198
+ expect(types).toContain('url-param');
199
+ expect(types).toContain('request-body');
200
+ });
201
+ it('detects WebSocket message sources', () => {
202
+ const file = makeFile({
203
+ relativePath: 'src/ws.ts',
204
+ content: `ws.on('message', (data) => { process(data); });`,
205
+ });
206
+ const sources = findSources([file]);
207
+ expect(sources.length).toBeGreaterThanOrEqual(1);
208
+ expect(sources[0].type).toBe('websocket');
209
+ });
210
+ it('detects file upload sources', () => {
211
+ const file = makeFile({
212
+ relativePath: 'src/upload.ts',
213
+ content: `const upload = multer({ dest: 'uploads/' });
214
+ app.post('/upload', (req, res) => { const f = req.files; });`,
215
+ });
216
+ const sources = findSources([file]);
217
+ const types = sources.map(s => s.type);
218
+ expect(types).toContain('file-upload');
219
+ });
220
+ it('includes correct line numbers', () => {
221
+ const file = makeFile({
222
+ relativePath: 'src/routes.ts',
223
+ content: `// line 1
224
+ // line 2
225
+ const x = req.body;`,
226
+ });
227
+ const sources = findSources([file]);
228
+ expect(sources.length).toBeGreaterThanOrEqual(1);
229
+ expect(sources[0].line).toBe(3);
230
+ });
231
+ it('returns empty for files with no sources', () => {
232
+ const file = makeFile({
233
+ relativePath: 'src/utils.ts',
234
+ content: `export function add(a: number, b: number) { return a + b; }`,
235
+ });
236
+ const sources = findSources([file]);
237
+ expect(sources).toHaveLength(0);
238
+ });
239
+ });
240
+ // ---------------------------------------------------------------------------
241
+ // findSinks
242
+ // ---------------------------------------------------------------------------
243
+ describe('findSinks', () => {
244
+ it('detects SQL query sinks', () => {
245
+ const file = makeFile({
246
+ relativePath: 'src/db.ts',
247
+ content: `
248
+ const result = await db.query(\`SELECT * FROM users WHERE id = \${id}\`);
249
+ pool.query('INSERT INTO logs VALUES ($1)', [msg]);`,
250
+ });
251
+ const sinks = findSinks([file]);
252
+ expect(sinks.length).toBeGreaterThanOrEqual(2);
253
+ expect(sinks.every(s => s.type === 'sql-query')).toBe(true);
254
+ });
255
+ it('detects command execution sinks', () => {
256
+ const file = makeFile({
257
+ relativePath: 'src/exec.ts',
258
+ content: `
259
+ const { execSync } = require('child_process');
260
+ execSync('ls ' + userInput);
261
+ spawn('bash', ['-c', cmd]);`,
262
+ });
263
+ const sinks = findSinks([file]);
264
+ const types = sinks.map(s => s.type);
265
+ expect(types).toContain('command-exec');
266
+ });
267
+ it('detects file operation sinks', () => {
268
+ const file = makeFile({
269
+ relativePath: 'src/files.ts',
270
+ content: `
271
+ fs.readFile(userPath, 'utf8', cb);
272
+ fs.writeFileSync(outPath, data);`,
273
+ });
274
+ const sinks = findSinks([file]);
275
+ expect(sinks.length).toBeGreaterThanOrEqual(2);
276
+ expect(sinks.every(s => s.type === 'file-op')).toBe(true);
277
+ });
278
+ it('detects redirect sinks', () => {
279
+ const file = makeFile({
280
+ relativePath: 'src/redirect.ts',
281
+ content: `
282
+ res.redirect(req.query.next);
283
+ location.href = url;`,
284
+ });
285
+ const sinks = findSinks([file]);
286
+ const types = sinks.map(s => s.type);
287
+ expect(types).toContain('redirect');
288
+ });
289
+ it('detects XSS sinks', () => {
290
+ const file = makeFile({
291
+ relativePath: 'src/render.tsx',
292
+ content: `
293
+ el.innerHTML = userContent;
294
+ <div dangerouslySetInnerHTML={{ __html: html }} />`,
295
+ });
296
+ const sinks = findSinks([file]);
297
+ const types = sinks.map(s => s.type);
298
+ expect(types).toContain('inner-html');
299
+ });
300
+ it('detects eval sinks', () => {
301
+ const file = makeFile({
302
+ relativePath: 'src/eval.ts',
303
+ content: `
304
+ eval(userCode);
305
+ const fn = new Function('x', body);`,
306
+ });
307
+ const sinks = findSinks([file]);
308
+ const types = sinks.map(s => s.type);
309
+ expect(types).toContain('eval');
310
+ });
311
+ it('detects response write sinks', () => {
312
+ const file = makeFile({
313
+ relativePath: 'src/api.ts',
314
+ content: `res.send(data); res.json({ ok: true });`,
315
+ });
316
+ const sinks = findSinks([file]);
317
+ expect(sinks.length).toBeGreaterThanOrEqual(2);
318
+ expect(sinks.every(s => s.type === 'response-write')).toBe(true);
319
+ });
320
+ it('detects Python sinks', () => {
321
+ const file = makeFile({
322
+ relativePath: 'app/views.py',
323
+ content: `
324
+ cursor.execute(f"SELECT * FROM users WHERE name = '{name}'")
325
+ os.system('rm ' + path)
326
+ subprocess.run(['ls', user_dir])`,
327
+ });
328
+ const sinks = findSinks([file]);
329
+ expect(sinks.length).toBeGreaterThanOrEqual(3);
330
+ const types = sinks.map(s => s.type);
331
+ expect(types).toContain('sql-query');
332
+ expect(types).toContain('command-exec');
333
+ });
334
+ it('detects Java sinks', () => {
335
+ const file = makeFile({
336
+ relativePath: 'src/Dao.java',
337
+ content: `
338
+ statement.executeQuery("SELECT * FROM users WHERE id = " + id);
339
+ Runtime.getRuntime().exec(cmd);
340
+ response.sendRedirect(url);`,
341
+ });
342
+ const sinks = findSinks([file]);
343
+ expect(sinks.length).toBeGreaterThanOrEqual(3);
344
+ });
345
+ it('includes correct line numbers', () => {
346
+ const file = makeFile({
347
+ relativePath: 'src/db.ts',
348
+ content: `// line 1
349
+ // line 2
350
+ // line 3
351
+ db.query(sql);`,
352
+ });
353
+ const sinks = findSinks([file]);
354
+ expect(sinks.length).toBeGreaterThanOrEqual(1);
355
+ expect(sinks[0].line).toBe(4);
356
+ });
357
+ it('returns empty for files with no sinks', () => {
358
+ const file = makeFile({
359
+ relativePath: 'src/types.ts',
360
+ content: `export interface User { id: number; name: string; }`,
361
+ });
362
+ const sinks = findSinks([file]);
363
+ expect(sinks).toHaveLength(0);
364
+ });
365
+ });
366
+ // ---------------------------------------------------------------------------
367
+ // buildTaintContext
368
+ // ---------------------------------------------------------------------------
369
+ describe('buildTaintContext', () => {
370
+ it('builds context with local sources and sinks', () => {
371
+ const file = makeFile({
372
+ relativePath: 'src/handler.ts',
373
+ content: `
374
+ const id = req.params.id;
375
+ db.query(\`SELECT * FROM users WHERE id = \${id}\`);`,
376
+ });
377
+ const sources = findSources([file]);
378
+ const sinks = findSinks([file]);
379
+ const ctx = buildTaintContext(file, [file], [], sources, sinks);
380
+ expect(ctx.file).toBe('src/handler.ts');
381
+ expect(ctx.sources.length).toBeGreaterThan(0);
382
+ expect(ctx.sinks.length).toBeGreaterThan(0);
383
+ });
384
+ it('traces cross-file data flow: source in importer, sink in target', () => {
385
+ const routeFile = makeFile({
386
+ relativePath: 'src/routes.ts',
387
+ content: `
388
+ import { getUser } from './db.js';
389
+ app.get('/user/:id', (req, res) => {
390
+ const user = getUser(req.params.id);
391
+ res.json(user);
392
+ });`,
393
+ imports: ['./db.js'],
394
+ });
395
+ const dbFile = makeFile({
396
+ relativePath: 'src/db.ts',
397
+ content: `
398
+ export function getUser(id: string) {
399
+ return db.query(\`SELECT * FROM users WHERE id = \${id}\`);
400
+ }`,
401
+ exports: ['getUser'],
402
+ });
403
+ const allFiles = [routeFile, dbFile];
404
+ const importGraph = buildImportGraph(allFiles);
405
+ const sources = findSources(allFiles);
406
+ const sinks = findSinks(allFiles);
407
+ // Build context for the db file (which has the sink)
408
+ const ctx = buildTaintContext(dbFile, allFiles, importGraph, sources, sinks);
409
+ expect(ctx.sinks.length).toBeGreaterThan(0);
410
+ // The route file (which has sources) should appear as a related file
411
+ expect(ctx.relatedFiles.some(rf => rf.path === 'src/routes.ts')).toBe(true);
412
+ expect(ctx.dataFlowPaths.length).toBeGreaterThan(0);
413
+ });
414
+ it('traces cross-file data flow: source in target, sink in importer', () => {
415
+ const routeFile = makeFile({
416
+ relativePath: 'src/routes.ts',
417
+ content: `
418
+ import { sanitize } from './utils.js';
419
+ app.get('/search', (req, res) => {
420
+ const q = req.query.q;
421
+ res.send(sanitize(q));
422
+ });`,
423
+ imports: ['./utils.js'],
424
+ exports: [],
425
+ });
426
+ const utilFile = makeFile({
427
+ relativePath: 'src/utils.ts',
428
+ content: `export function sanitize(s: string) { return s; }`,
429
+ exports: ['sanitize'],
430
+ });
431
+ const allFiles = [routeFile, utilFile];
432
+ const importGraph = buildImportGraph(allFiles);
433
+ const sources = findSources(allFiles);
434
+ const sinks = findSinks(allFiles);
435
+ // Build context for the route file (which has both source and sink)
436
+ const ctx = buildTaintContext(routeFile, allFiles, importGraph, sources, sinks);
437
+ expect(ctx.sources.length).toBeGreaterThan(0);
438
+ expect(ctx.sinks.length).toBeGreaterThan(0);
439
+ });
440
+ it('returns empty related files when no cross-file connections', () => {
441
+ const file = makeFile({
442
+ relativePath: 'src/isolated.ts',
443
+ content: `db.query('SELECT 1');`,
444
+ });
445
+ const sinks = findSinks([file]);
446
+ const ctx = buildTaintContext(file, [file], [], [], sinks);
447
+ expect(ctx.relatedFiles).toHaveLength(0);
448
+ expect(ctx.dataFlowPaths).toHaveLength(0);
449
+ });
450
+ it('handles complex multi-file chains', () => {
451
+ const controllerFile = makeFile({
452
+ relativePath: 'src/controller.ts',
453
+ content: `
454
+ import { processOrder } from './service.js';
455
+ app.post('/order', (req, res) => {
456
+ const result = processOrder(req.body);
457
+ res.json(result);
458
+ });`,
459
+ imports: ['./service.js'],
460
+ });
461
+ const serviceFile = makeFile({
462
+ relativePath: 'src/service.ts',
463
+ content: `
464
+ import { saveOrder } from './repo.js';
465
+ export function processOrder(data: any) {
466
+ return saveOrder(data);
467
+ }`,
468
+ imports: ['./repo.js'],
469
+ exports: ['processOrder'],
470
+ });
471
+ const repoFile = makeFile({
472
+ relativePath: 'src/repo.ts',
473
+ content: `
474
+ export function saveOrder(data: any) {
475
+ return db.query(\`INSERT INTO orders VALUES (\${data.id})\`);
476
+ }`,
477
+ exports: ['saveOrder'],
478
+ });
479
+ const allFiles = [controllerFile, serviceFile, repoFile];
480
+ const importGraph = buildImportGraph(allFiles);
481
+ const sources = findSources(allFiles);
482
+ const sinks = findSinks(allFiles);
483
+ // The repo file has the sink; the controller file has the source
484
+ const ctx = buildTaintContext(repoFile, allFiles, importGraph, sources, sinks);
485
+ expect(ctx.sinks.length).toBeGreaterThan(0);
486
+ // Service file imports repo, and controller imports service
487
+ // The 2nd-degree traversal should find the controller via the service
488
+ expect(ctx.relatedFiles.length).toBeGreaterThan(0);
489
+ });
490
+ });
491
+ // ---------------------------------------------------------------------------
492
+ // formatTaintContext
493
+ // ---------------------------------------------------------------------------
494
+ describe('formatTaintContext', () => {
495
+ it('returns empty string when no cross-file context', () => {
496
+ const ctx = {
497
+ file: 'src/isolated.ts',
498
+ sources: [],
499
+ sinks: [{ file: 'src/isolated.ts', line: 5, type: 'sql-query', identifier: 'db.query(' }],
500
+ dataFlowPaths: [],
501
+ relatedFiles: [],
502
+ };
503
+ expect(formatTaintContext(ctx)).toBe('');
504
+ });
505
+ it('formats sources, sinks, data flows, and related files', () => {
506
+ const ctx = {
507
+ file: 'src/db.ts',
508
+ sources: [
509
+ { file: 'src/db.ts', line: 3, type: 'request-param', identifier: 'req.params' },
510
+ ],
511
+ sinks: [
512
+ { file: 'src/db.ts', line: 10, type: 'sql-query', identifier: 'db.query(' },
513
+ ],
514
+ dataFlowPaths: [
515
+ 'request-param in src/routes.ts:5 → getUser → sql-query in src/db.ts:10',
516
+ ],
517
+ relatedFiles: [
518
+ {
519
+ path: 'src/routes.ts',
520
+ relevance: 'calls getUser from target',
521
+ snippet: 'L5: const user = getUser(req.params.id);',
522
+ },
523
+ ],
524
+ };
525
+ const output = formatTaintContext(ctx);
526
+ expect(output).toContain('SOURCES');
527
+ expect(output).toContain('request-param');
528
+ expect(output).toContain('SINKS');
529
+ expect(output).toContain('sql-query');
530
+ expect(output).toContain('DATA FLOW PATHS');
531
+ expect(output).toContain('request-param in src/routes.ts:5');
532
+ expect(output).toContain('RELATED FILES');
533
+ expect(output).toContain('src/routes.ts');
534
+ expect(output).toContain('getUser');
535
+ });
536
+ it('limits output to prevent prompt bloat', () => {
537
+ const manySources = Array.from({ length: 20 }, (_, i) => ({
538
+ file: 'src/big.ts',
539
+ line: i + 1,
540
+ type: 'request-param',
541
+ identifier: `req.params.p${i}`,
542
+ }));
543
+ const ctx = {
544
+ file: 'src/big.ts',
545
+ sources: manySources,
546
+ sinks: [],
547
+ dataFlowPaths: ['some flow'],
548
+ relatedFiles: [{ path: 'src/other.ts', relevance: 'test', snippet: 'code' }],
549
+ };
550
+ const output = formatTaintContext(ctx);
551
+ // Should only show at most 10 sources
552
+ const sourceMatches = output.match(/request-param/g) || [];
553
+ expect(sourceMatches.length).toBeLessThanOrEqual(10);
554
+ });
555
+ });
556
+ //# sourceMappingURL=taint-analysis.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taint-analysis.test.js","sourceRoot":"","sources":["../../../src/hunt/__tests__/taint-analysis.test.ts"],"names":[],"mappings":"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"}
@@ -21,8 +21,8 @@ describe('Template registry', () => {
21
21
  it('returns undefined for unknown id', () => {
22
22
  expect(getTemplateById('nonexistent')).toBeUndefined();
23
23
  });
24
- it('has exactly 10 templates', () => {
25
- expect(getAllTemplates()).toHaveLength(10);
24
+ it('has 24 built-in templates', () => {
25
+ expect(getAllTemplates()).toHaveLength(24);
26
26
  });
27
27
  it('each template has unique id', () => {
28
28
  const ids = getAllTemplates().map(t => t.id);
@@ -1 +1 @@
1
- {"version":3,"file":"templates.test.js","sourceRoot":"","sources":["../../../src/hunt/__tests__/templates.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEzE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;QACpC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;YAC1B,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACnC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;YACpD,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"templates.test.js","sourceRoot":"","sources":["../../../src/hunt/__tests__/templates.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEzE,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAC7B,MAAM,SAAS,GAAG,eAAe,EAAE,CAAC;QACpC,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;YAC1B,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;YACnC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YACjD,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;YAClD,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;YACpD,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QACpD,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,CAAC,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;QACzC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;QACxB,MAAM,CAAC,CAAE,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import type { VulnerabilityTemplate, HuntHypothesis, HuntFinding } from '../types.js';
2
2
  import type { DiscoveredFile } from './discovery.js';
3
3
  import type { LLMProvider } from '../runtime/types.js';
4
- export declare function buildDeepDivePrompt(template: VulnerabilityTemplate, hypothesis: HuntHypothesis, file: DiscoveredFile): {
4
+ export declare function buildDeepDivePrompt(template: VulnerabilityTemplate, hypothesis: HuntHypothesis, file: DiscoveredFile, taintContext?: string): {
5
5
  systemPrompt: string;
6
6
  userPrompt: string;
7
7
  };
8
- export declare function runDeepDive(template: VulnerabilityTemplate, hypothesis: HuntHypothesis, file: DiscoveredFile, provider: LLMProvider): Promise<HuntFinding | null>;
8
+ export declare function runDeepDive(template: VulnerabilityTemplate, hypothesis: HuntHypothesis, file: DiscoveredFile, provider: LLMProvider, taintContext?: string): Promise<HuntFinding | null>;
@@ -1,5 +1,5 @@
1
1
  import { safeParseJSON } from './parse-utils.js';
2
- export function buildDeepDivePrompt(template, hypothesis, file) {
2
+ export function buildDeepDivePrompt(template, hypothesis, file, taintContext) {
3
3
  const systemPrompt = `You are an expert security researcher writing a bug bounty report.
4
4
 
5
5
  VULNERABILITY CLASS: ${template.name} (${template.cwe})
@@ -41,11 +41,11 @@ ${context ? `CONTEXT:\n${context}\n` : ''}
41
41
  ${file.content}
42
42
  </analyzed-code>
43
43
 
44
- Verify whether this vulnerability is real and exploitable. If real, write a complete bug bounty report. If false positive, explain why.`;
44
+ Verify whether this vulnerability is real and exploitable. If real, write a complete bug bounty report. If false positive, explain why.${taintContext ? `\n\nCROSS-FILE DATA FLOW:\n${taintContext}` : ''}`;
45
45
  return { systemPrompt, userPrompt };
46
46
  }
47
- export async function runDeepDive(template, hypothesis, file, provider) {
48
- const { systemPrompt, userPrompt } = buildDeepDivePrompt(template, hypothesis, file);
47
+ export async function runDeepDive(template, hypothesis, file, provider, taintContext) {
48
+ const { systemPrompt, userPrompt } = buildDeepDivePrompt(template, hypothesis, file, taintContext);
49
49
  try {
50
50
  const response = await provider.complete({
51
51
  model: 'claude-sonnet-4-6',
@@ -1 +1 @@
1
- {"version":3,"file":"deep-dive.js","sourceRoot":"","sources":["../../src/hunt/deep-dive.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deep-dive.js","sourceRoot":"","sources":["../../src/hunt/deep-dive.ts"],"names":[],"mappings":"AAGA,OAAO,EAAmB,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,UAAU,mBAAmB,CACjC,QAA+B,EAC/B,UAA0B,EAC1B,IAAoB,EACpB,YAAqB;IAErB,MAAM,YAAY,GAAG;;uBAEA,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,GAAG;;EAEnD,QAAQ,CAAC,cAAc;;;EAGvB,QAAQ,CAAC,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAGpD,QAAQ,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;EAgBrD,CAAC;IAED,MAAM,OAAO,GAAG;QACd,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;QAClE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;QAClE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI;KACzE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE7B,MAAM,UAAU,GAAG,eAAe,UAAU,CAAC,OAAO;qBACjC,UAAU,CAAC,eAAe;UACrC,UAAU,CAAC,MAAM;QACnB,IAAI,CAAC,YAAY,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE;EACtE,OAAO,CAAC,CAAC,CAAC,aAAa,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE;;EAEvC,IAAI,CAAC,OAAO;;;yIAG2H,YAAY,CAAC,CAAC,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAE1M,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,QAA+B,EAC/B,UAA0B,EAC1B,IAAoB,EACpB,QAAqB,EACrB,YAAqB;IAErB,MAAM,EAAE,YAAY,EAAE,UAAU,EAAE,GAAG,mBAAmB,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;IAEnG,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC;YACvC,KAAK,EAAE,mBAAmB;YAC1B,SAAS,EAAE,IAAI;YACf,YAAY;YACZ,UAAU;YACV,WAAW,EAAE,CAAC;SACf,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QAC/C,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,KAAK,CAAC,iEAAiE,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC;YAChG,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEnD,OAAO;YACL,YAAY,EAAE,UAAU,CAAC,EAAE;YAC3B,UAAU,EAAE,QAAQ,CAAC,EAAE;YACvB,IAAI,EAAE,IAAI,CAAC,YAAY;YACvB,IAAI,EAAE,UAAU,CAAC,IAAI;YACrB,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,QAAQ,CAAC,GAAG;YAC/B,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,cAAc,EAAE,MAAM,CAAC,eAAe,IAAI,EAAE;YAC5C,iBAAiB,EAAE,MAAM,CAAC,kBAAkB,IAAI,EAAE;YAClD,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,EAAE;YAC/B,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,EAAE;YAC3C,SAAS,EAAE,IAAI;SAChB,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,+CAA+C,UAAU,CAAC,EAAE,KAAK,GAAG,EAAE,CAAC,CAAC;QACtF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}