jaku.sh 1.0.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 (69) hide show
  1. package/LICENSE +52 -0
  2. package/README.md +636 -0
  3. package/action.yml +264 -0
  4. package/bin/jaku +2 -0
  5. package/package.json +62 -0
  6. package/src/agents/ai-agent.js +175 -0
  7. package/src/agents/api-agent.js +95 -0
  8. package/src/agents/base-agent.js +158 -0
  9. package/src/agents/crawl-agent.js +175 -0
  10. package/src/agents/event-bus.js +59 -0
  11. package/src/agents/findings-ledger.js +410 -0
  12. package/src/agents/logic-agent.js +144 -0
  13. package/src/agents/orchestrator.js +323 -0
  14. package/src/agents/qa-agent.js +149 -0
  15. package/src/agents/security-agent.js +211 -0
  16. package/src/cli.js +423 -0
  17. package/src/core/accessibility-checker.js +171 -0
  18. package/src/core/ai/ai-endpoint-detector.js +227 -0
  19. package/src/core/ai/guardrail-prober.js +362 -0
  20. package/src/core/ai/indirect-injector.js +106 -0
  21. package/src/core/ai/jailbreak-tester.js +212 -0
  22. package/src/core/ai/model-dos-tester.js +174 -0
  23. package/src/core/ai/model-fingerprinter.js +246 -0
  24. package/src/core/ai/multi-turn-attacker.js +297 -0
  25. package/src/core/ai/output-analyzer.js +182 -0
  26. package/src/core/ai/prompt-injector.js +543 -0
  27. package/src/core/ai/system-prompt-extractor.js +244 -0
  28. package/src/core/api/api-key-auditor.js +266 -0
  29. package/src/core/api/auth-flow-tester.js +430 -0
  30. package/src/core/api/cors-ws-tester.js +263 -0
  31. package/src/core/api/graphql-tester.js +287 -0
  32. package/src/core/api/oauth-prober.js +343 -0
  33. package/src/core/auth-manager.js +902 -0
  34. package/src/core/broken-flow-detector.js +207 -0
  35. package/src/core/browser-manager.js +119 -0
  36. package/src/core/console-monitor.js +111 -0
  37. package/src/core/crawler.js +430 -0
  38. package/src/core/csr-waiter.js +410 -0
  39. package/src/core/form-validator.js +240 -0
  40. package/src/core/logic/abuse-pattern-scanner.js +291 -0
  41. package/src/core/logic/access-boundary-tester.js +448 -0
  42. package/src/core/logic/business-rule-inferrer.js +196 -0
  43. package/src/core/logic/graphql-auditor.js +298 -0
  44. package/src/core/logic/parameter-polluter.js +212 -0
  45. package/src/core/logic/pricing-exploiter.js +299 -0
  46. package/src/core/logic/race-condition-detector.js +222 -0
  47. package/src/core/logic/workflow-enforcer.js +284 -0
  48. package/src/core/performance-checker.js +204 -0
  49. package/src/core/responsive-checker.js +228 -0
  50. package/src/core/security/cors-prober.js +150 -0
  51. package/src/core/security/csrf-prober.js +217 -0
  52. package/src/core/security/dependency-auditor.js +182 -0
  53. package/src/core/security/file-upload-tester.js +340 -0
  54. package/src/core/security/header-analyzer.js +324 -0
  55. package/src/core/security/infra-scanner.js +391 -0
  56. package/src/core/security/path-traversal.js +112 -0
  57. package/src/core/security/prototype-pollution.js +147 -0
  58. package/src/core/security/secret-detector.js +517 -0
  59. package/src/core/security/sqli-prober.js +257 -0
  60. package/src/core/security/tls-checker.js +223 -0
  61. package/src/core/security/xss-scanner.js +225 -0
  62. package/src/core/test-generator.js +339 -0
  63. package/src/core/test-runner.js +398 -0
  64. package/src/reporting/diff-reporter.js +172 -0
  65. package/src/reporting/report-generator.js +408 -0
  66. package/src/reporting/sarif-generator.js +190 -0
  67. package/src/utils/config.js +57 -0
  68. package/src/utils/finding.js +67 -0
  69. package/src/utils/logger.js +50 -0
package/action.yml ADDED
@@ -0,0 +1,264 @@
1
+ name: 'JAKU Security Scan'
2
+ description: 'Run JAKU autonomous security & QA scanning on your web application'
3
+ author: 'JAKU'
4
+ branding:
5
+ icon: 'shield'
6
+ color: 'green'
7
+
8
+ inputs:
9
+ target-url:
10
+ description: 'Target URL to scan'
11
+ required: true
12
+ config-path:
13
+ description: 'Path to jaku.config.json'
14
+ required: false
15
+ default: ''
16
+ modules:
17
+ description: 'Comma-separated modules to run (qa,security,ai,logic,api)'
18
+ required: false
19
+ default: 'qa,security,ai,logic,api'
20
+ severity-threshold:
21
+ description: 'Minimum severity to report (critical|high|medium|low)'
22
+ required: false
23
+ default: 'low'
24
+ fail-on-severity:
25
+ description: 'Fail the action if findings at this severity or above are found (critical|high|medium|low|none)'
26
+ required: false
27
+ default: 'high'
28
+ sarif-upload:
29
+ description: 'Upload SARIF results to GitHub Security tab'
30
+ required: false
31
+ default: 'true'
32
+ comment-on-pr:
33
+ description: 'Post scan summary as PR comment'
34
+ required: false
35
+ default: 'true'
36
+ auth-username:
37
+ description: 'Username for authenticated scanning'
38
+ required: false
39
+ default: ''
40
+ auth-password:
41
+ description: 'Password for authenticated scanning'
42
+ required: false
43
+ default: ''
44
+ auth-strategy:
45
+ description: 'Authentication strategy (auto|form|api|cookie)'
46
+ required: false
47
+ default: 'auto'
48
+ max-pages:
49
+ description: 'Maximum pages to crawl'
50
+ required: false
51
+ default: '50'
52
+ verbose:
53
+ description: 'Enable verbose logging'
54
+ required: false
55
+ default: 'false'
56
+
57
+ outputs:
58
+ report-path:
59
+ description: 'Path to the generated report directory'
60
+ sarif-path:
61
+ description: 'Path to the SARIF report file'
62
+ findings-count:
63
+ description: 'Total number of findings'
64
+ critical-count:
65
+ description: 'Number of critical findings'
66
+ high-count:
67
+ description: 'Number of high findings'
68
+ exit-code:
69
+ description: 'Exit code (0 = pass, 1 = findings above threshold)'
70
+
71
+ runs:
72
+ using: 'composite'
73
+ steps:
74
+ - name: Setup Node.js
75
+ uses: actions/setup-node@v4
76
+ with:
77
+ node-version: '20'
78
+
79
+ - name: Install JAKU
80
+ shell: bash
81
+ run: |
82
+ cd ${{ github.action_path }}
83
+ npm ci --production 2>/dev/null || npm install --production
84
+
85
+ - name: Install Playwright browsers
86
+ shell: bash
87
+ run: |
88
+ cd ${{ github.action_path }}
89
+ npx playwright install chromium --with-deps
90
+
91
+ - name: Run JAKU Scan
92
+ id: scan
93
+ shell: bash
94
+ env:
95
+ JAKU_TARGET_URL: ${{ inputs.target-url }}
96
+ JAKU_MODULES: ${{ inputs.modules }}
97
+ JAKU_SEVERITY: ${{ inputs.severity-threshold }}
98
+ JAKU_FAIL_ON: ${{ inputs.fail-on-severity }}
99
+ JAKU_CONFIG: ${{ inputs.config-path }}
100
+ JAKU_AUTH_USER: ${{ inputs.auth-username }}
101
+ JAKU_AUTH_PASS: ${{ inputs.auth-password }}
102
+ JAKU_AUTH_STRATEGY: ${{ inputs.auth-strategy }}
103
+ JAKU_MAX_PAGES: ${{ inputs.max-pages }}
104
+ JAKU_VERBOSE: ${{ inputs.verbose }}
105
+ run: |
106
+ REPORT_DIR="${{ runner.temp }}/jaku-reports"
107
+
108
+ # Build command
109
+ CMD="node ${{ github.action_path }}/src/cli.js scan \"${JAKU_TARGET_URL}\""
110
+ CMD="${CMD} -m ${JAKU_MODULES}"
111
+ CMD="${CMD} -s ${JAKU_SEVERITY}"
112
+ CMD="${CMD} -o ${REPORT_DIR}"
113
+ CMD="${CMD} --max-pages ${JAKU_MAX_PAGES}"
114
+ CMD="${CMD} --prod-safe"
115
+
116
+ if [ -n "${JAKU_CONFIG}" ]; then
117
+ CMD="${CMD} -c ${JAKU_CONFIG}"
118
+ fi
119
+
120
+ if [ -n "${JAKU_AUTH_USER}" ] && [ -n "${JAKU_AUTH_PASS}" ]; then
121
+ CMD="${CMD} --username ${JAKU_AUTH_USER} --password ${JAKU_AUTH_PASS} --auth-strategy ${JAKU_AUTH_STRATEGY}"
122
+ fi
123
+
124
+ if [ "${JAKU_VERBOSE}" = "true" ]; then
125
+ CMD="${CMD} --verbose"
126
+ fi
127
+
128
+ # Run scan
129
+ eval ${CMD} || true
130
+
131
+ # Parse results
132
+ if [ -f "${REPORT_DIR}/report.json" ]; then
133
+ eval $(node --input-type=module -e "
134
+ import { readFileSync } from 'fs';
135
+ const r = JSON.parse(readFileSync('${REPORT_DIR}/report.json', 'utf-8'));
136
+ const s = r.dedupSummary || r.summary;
137
+ console.log('FINDINGS=' + s.total);
138
+ console.log('CRITICAL=' + s.critical);
139
+ console.log('HIGH=' + s.high);
140
+ console.log('MEDIUM=' + s.medium);
141
+ console.log('LOW=' + s.low);
142
+ ")
143
+ else
144
+ FINDINGS=0; CRITICAL=0; HIGH=0; MEDIUM=0; LOW=0
145
+ fi
146
+
147
+ echo "report-path=${REPORT_DIR}" >> $GITHUB_OUTPUT
148
+ echo "sarif-path=${REPORT_DIR}/report.sarif" >> $GITHUB_OUTPUT
149
+ echo "findings-count=${FINDINGS}" >> $GITHUB_OUTPUT
150
+ echo "critical-count=${CRITICAL}" >> $GITHUB_OUTPUT
151
+ echo "high-count=${HIGH}" >> $GITHUB_OUTPUT
152
+
153
+ # Determine exit code based on fail-on-severity
154
+ EXIT_CODE=0
155
+ case "${JAKU_FAIL_ON}" in
156
+ critical) [ "${CRITICAL}" -gt 0 ] && EXIT_CODE=1 ;;
157
+ high) [ "${CRITICAL}" -gt 0 ] || [ "${HIGH}" -gt 0 ] && EXIT_CODE=1 ;;
158
+ medium) [ "${CRITICAL}" -gt 0 ] || [ "${HIGH}" -gt 0 ] || [ "${MEDIUM}" -gt 0 ] && EXIT_CODE=1 ;;
159
+ low) [ "${FINDINGS}" -gt 0 ] && EXIT_CODE=1 ;;
160
+ none) EXIT_CODE=0 ;;
161
+ esac
162
+
163
+ echo "exit-code=${EXIT_CODE}" >> $GITHUB_OUTPUT
164
+
165
+ - name: Upload SARIF to GitHub Security
166
+ if: inputs.sarif-upload == 'true' && hashFiles(steps.scan.outputs.sarif-path) != ''
167
+ uses: github/codeql-action/upload-sarif@v3
168
+ with:
169
+ sarif_file: ${{ steps.scan.outputs.sarif-path }}
170
+ category: 'jaku-security-scan'
171
+ continue-on-error: true
172
+
173
+ - name: Comment on PR
174
+ if: inputs.comment-on-pr == 'true' && github.event_name == 'pull_request'
175
+ uses: actions/github-script@v7
176
+ with:
177
+ script: |
178
+ const fs = require('fs');
179
+ const reportPath = '${{ steps.scan.outputs.report-path }}/report.json';
180
+
181
+ let body = '## 🛡️ JAKU Security Scan Results\n\n';
182
+
183
+ if (fs.existsSync(reportPath)) {
184
+ const report = JSON.parse(fs.readFileSync(reportPath, 'utf-8'));
185
+ const s = report.dedupSummary || report.summary;
186
+ const ds = report.dedupStats;
187
+
188
+ // Status badge
189
+ const hasIssues = s.critical > 0 || s.high > 0;
190
+ body += hasIssues
191
+ ? '> ⚠️ **Security issues detected** — review required\n\n'
192
+ : '> ✅ **No critical or high severity issues found**\n\n';
193
+
194
+ // Summary table
195
+ body += '| Severity | Count |\n|----------|-------|\n';
196
+ if (s.critical > 0) body += `| 🔴 Critical | ${s.critical} |\n`;
197
+ if (s.high > 0) body += `| 🟠 High | ${s.high} |\n`;
198
+ if (s.medium > 0) body += `| 🟡 Medium | ${s.medium} |\n`;
199
+ if (s.low > 0) body += `| 🔵 Low | ${s.low} |\n`;
200
+ body += `| **Total** | **${s.total}** |\n\n`;
201
+
202
+ // Dedup stats
203
+ if (ds && ds.duplicatesRemoved > 0) {
204
+ body += `*${ds.rawCount} raw findings deduplicated to ${ds.dedupedCount} unique (${ds.reductionPercent}% reduction)*\n\n`;
205
+ }
206
+
207
+ // Top findings
208
+ const findings = report.findings || [];
209
+ if (findings.length > 0) {
210
+ body += '### Top Findings\n\n';
211
+ for (const f of findings.slice(0, 5)) {
212
+ const icon = { critical: '🔴', high: '🟠', medium: '🟡', low: '🔵', info: '⚪' }[f.severity] || '⚪';
213
+ body += `- ${icon} **${f.title}** — ${f.affected_surface || f.affected_surfaces?.[0] || 'N/A'}\n`;
214
+ }
215
+ if (findings.length > 5) {
216
+ body += `\n*...and ${findings.length - 5} more. See full report in artifacts.*\n`;
217
+ }
218
+ }
219
+
220
+ body += '\n---\n*Scanned by [JAKU](https://github.com/jaku-security/jaku) v1.0.0*';
221
+ } else {
222
+ body += '⚠️ Scan completed but no report was generated. Check workflow logs for errors.';
223
+ }
224
+
225
+ // Find and update existing comment, or create new one
226
+ const { data: comments } = await github.rest.issues.listComments({
227
+ owner: context.repo.owner,
228
+ repo: context.repo.repo,
229
+ issue_number: context.issue.number,
230
+ });
231
+
232
+ const botComment = comments.find(c => c.body.includes('JAKU Security Scan Results'));
233
+
234
+ if (botComment) {
235
+ await github.rest.issues.updateComment({
236
+ owner: context.repo.owner,
237
+ repo: context.repo.repo,
238
+ comment_id: botComment.id,
239
+ body,
240
+ });
241
+ } else {
242
+ await github.rest.issues.createComment({
243
+ owner: context.repo.owner,
244
+ repo: context.repo.repo,
245
+ issue_number: context.issue.number,
246
+ body,
247
+ });
248
+ }
249
+
250
+ - name: Upload Report Artifacts
251
+ if: always()
252
+ uses: actions/upload-artifact@v4
253
+ with:
254
+ name: jaku-scan-report
255
+ path: ${{ steps.scan.outputs.report-path }}
256
+ retention-days: 30
257
+
258
+ - name: Check Threshold
259
+ if: steps.scan.outputs.exit-code == '1'
260
+ shell: bash
261
+ run: |
262
+ echo "::error::JAKU scan found findings at or above the '${{ inputs.fail-on-severity }}' severity threshold."
263
+ echo "Critical: ${{ steps.scan.outputs.critical-count }}, High: ${{ steps.scan.outputs.high-count }}, Total: ${{ steps.scan.outputs.findings-count }}"
264
+ exit 1
package/bin/jaku ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ import '../src/cli.js';
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "jaku.sh",
3
+ "version": "1.0.0",
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
+ "type": "module",
6
+ "main": "src/cli.js",
7
+ "bin": {
8
+ "jaku": "./bin/jaku"
9
+ },
10
+ "engines": {
11
+ "node": ">=20"
12
+ },
13
+ "files": [
14
+ "src/",
15
+ "bin/",
16
+ "action.yml",
17
+ "README.md"
18
+ ],
19
+ "scripts": {
20
+ "scan": "node src/cli.js scan",
21
+ "prepublishOnly": "node src/cli.js --help"
22
+ },
23
+ "keywords": [
24
+ "security",
25
+ "qa",
26
+ "testing",
27
+ "automation",
28
+ "playwright",
29
+ "scanning",
30
+ "xss",
31
+ "sql-injection",
32
+ "prompt-injection",
33
+ "ai-security",
34
+ "vulnerability-scanner",
35
+ "penetration-testing",
36
+ "vibe-coding",
37
+ "autonomous-testing",
38
+ "attack-chain"
39
+ ],
40
+ "author": {
41
+ "name": "Shantanu Pandey",
42
+ "url": "https://github.com/theshantanupandey"
43
+ },
44
+ "license": "SEE LICENSE IN LICENSE",
45
+ "homepage": "https://jakusec.dev",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/theshantanupandey/jaku.git"
49
+ },
50
+ "bugs": {
51
+ "url": "https://github.com/theshantanupandey/jaku/issues"
52
+ },
53
+ "dependencies": {
54
+ "chalk": "^5.3.0",
55
+ "commander": "^12.1.0",
56
+ "nanoid": "^5.0.9",
57
+ "ora": "^8.1.1",
58
+ "p-limit": "^7.3.0",
59
+ "playwright": "^1.49.1",
60
+ "winston": "^3.17.0"
61
+ }
62
+ }
@@ -0,0 +1,175 @@
1
+ import { BaseAgent } from './base-agent.js';
2
+ import { AIEndpointDetector } from '../core/ai/ai-endpoint-detector.js';
3
+ import { PromptInjector } from '../core/ai/prompt-injector.js';
4
+ import { JailbreakTester } from '../core/ai/jailbreak-tester.js';
5
+ import { SystemPromptExtractor } from '../core/ai/system-prompt-extractor.js';
6
+ import { OutputAnalyzer } from '../core/ai/output-analyzer.js';
7
+ import { GuardrailProber } from '../core/ai/guardrail-prober.js';
8
+ import { ModelDoSTester } from '../core/ai/model-dos-tester.js';
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
+
13
+ /**
14
+ * JAKU-AI — Prompt Injection & AI Abuse Detection Agent
15
+ *
16
+ * Pipeline:
17
+ * 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)
20
+ * 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)
23
+ * 7. Model DoS Testing (context bombing, token loops)
24
+ * 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
+ *
28
+ * Dependencies: JAKU-CRAWL (runs in Wave 2, parallel with QA + SEC)
29
+ */
30
+ export class AIAgent extends BaseAgent {
31
+ get name() { return 'JAKU-AI'; }
32
+ get dependencies() { return ['JAKU-CRAWL']; }
33
+
34
+ async _execute(context) {
35
+ const { config, logger, surfaceInventory } = context;
36
+
37
+ if (!surfaceInventory) {
38
+ throw new Error('No surface inventory available — JAKU-CRAWL must run first');
39
+ }
40
+
41
+ // Phase 1: Detect AI endpoints
42
+ this.progress('detect', 'Detecting AI-powered endpoints...', 0);
43
+
44
+ const detector = new AIEndpointDetector(logger);
45
+ const aiSurfaces = await detector.detect(surfaceInventory);
46
+
47
+ this._log(`Detected ${aiSurfaces.length} AI surfaces (${aiSurfaces.filter(s => s.confidence === 'confirmed').length} confirmed)`);
48
+ this.progress('detect', `Found ${aiSurfaces.length} AI endpoints`, 10);
49
+
50
+ if (aiSurfaces.length === 0) {
51
+ this._log('No AI endpoints detected — skipping AI abuse tests');
52
+ this.progress('complete', 'No AI endpoints found — scan skipped', 100);
53
+ return;
54
+ }
55
+
56
+ // Create shared sendMessage function for sub-modules
57
+ const injector = new PromptInjector(logger);
58
+ const sendMessage = injector._sendMessage.bind(injector);
59
+
60
+ // Phase 2: Prompt Injection
61
+ this.progress('injection', 'Testing for prompt injection...', 15);
62
+ try {
63
+ const injectionFindings = await injector.inject(aiSurfaces);
64
+ this.addFindings(injectionFindings);
65
+ this._log(`Prompt injection: ${injectionFindings.length} vulnerabilities`);
66
+ } catch (err) {
67
+ this._log(`Prompt injection testing failed: ${err.message}`, 'error');
68
+ }
69
+ this.progress('injection', 'Prompt injection testing complete', 30);
70
+
71
+ // Phase 3: Jailbreak Testing
72
+ this.progress('jailbreak', 'Testing jailbreak techniques...', 30);
73
+ try {
74
+ const tester = new JailbreakTester(logger);
75
+ const jailbreakFindings = await tester.test(aiSurfaces, sendMessage);
76
+ this.addFindings(jailbreakFindings);
77
+ this._log(`Jailbreak: ${jailbreakFindings.length} vulnerabilities`);
78
+ } catch (err) {
79
+ this._log(`Jailbreak testing failed: ${err.message}`, 'error');
80
+ }
81
+ this.progress('jailbreak', 'Jailbreak testing complete', 50);
82
+
83
+ // Phase 4: System Prompt Extraction
84
+ this.progress('extraction', 'Attempting system prompt extraction...', 50);
85
+ try {
86
+ const extractor = new SystemPromptExtractor(logger);
87
+ const extractionFindings = await extractor.extract(aiSurfaces, sendMessage);
88
+ this.addFindings(extractionFindings);
89
+ this._log(`System prompt extraction: ${extractionFindings.length} leaks`);
90
+ } catch (err) {
91
+ this._log(`System prompt extraction failed: ${err.message}`, 'error');
92
+ }
93
+ this.progress('extraction', 'System prompt extraction complete', 70);
94
+
95
+ // Phase 5: Output Analysis (AI-mediated XSS)
96
+ this.progress('output', 'Analyzing AI output sanitization...', 70);
97
+ try {
98
+ const analyzer = new OutputAnalyzer(logger);
99
+ const outputFindings = await analyzer.analyze(aiSurfaces, sendMessage);
100
+ this.addFindings(outputFindings);
101
+ this._log(`Output analysis: ${outputFindings.length} issues`);
102
+ } catch (err) {
103
+ this._log(`Output analysis failed: ${err.message}`, 'error');
104
+ }
105
+ this.progress('output', 'Output analysis complete', 85);
106
+
107
+ // Phase 6: Guardrail Probing
108
+ this.progress('guardrails', 'Probing AI guardrails...', 85);
109
+ try {
110
+ const prober = new GuardrailProber(logger);
111
+ const guardrailFindings = await prober.probe(aiSurfaces, sendMessage);
112
+ this.addFindings(guardrailFindings);
113
+ this._log(`Guardrails: ${guardrailFindings.length} bypasses`);
114
+ } catch (err) {
115
+ this._log(`Guardrail probing failed: ${err.message}`, 'error');
116
+ }
117
+ this.progress('guardrails', 'Guardrail probing complete', 80);
118
+
119
+ // Phase 7: Model DoS
120
+ this.progress('dos', 'Testing model DoS vectors...', 80);
121
+ try {
122
+ const dosTester = new ModelDoSTester(logger);
123
+ const dosFindings = await dosTester.test(aiSurfaces, sendMessage);
124
+ this.addFindings(dosFindings);
125
+ this._log(`Model DoS: ${dosFindings.length} issues`);
126
+ } catch (err) {
127
+ this._log(`Model DoS testing failed: ${err.message}`, 'error');
128
+ }
129
+ this.progress('dos', 'Model DoS testing complete', 90);
130
+
131
+ // Phase 8: Indirect Injection
132
+ this.progress('indirect', 'Testing indirect prompt injection...', 90);
133
+ try {
134
+ const indirectInjector = new IndirectInjector(logger);
135
+ const indirectFindings = await indirectInjector.test(aiSurfaces, sendMessage);
136
+ this.addFindings(indirectFindings);
137
+ this._log(`Indirect injection: ${indirectFindings.length} vulnerabilities`);
138
+ } catch (err) {
139
+ this._log(`Indirect injection testing failed: ${err.message}`, 'error');
140
+ }
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);
170
+
171
+ this.progress('complete', `AI scan complete — ${this._findings.length} total findings`, 100);
172
+ }
173
+ }
174
+
175
+ export default AIAgent;
@@ -0,0 +1,95 @@
1
+ import { BaseAgent } from './base-agent.js';
2
+ import { AuthFlowTester } from '../core/api/auth-flow-tester.js';
3
+ import { OAuthProber } from '../core/api/oauth-prober.js';
4
+ import { APIKeyAuditor } from '../core/api/api-key-auditor.js';
5
+ import { GraphQLTester } from '../core/api/graphql-tester.js';
6
+ import { CORSWSTester } from '../core/api/cors-ws-tester.js';
7
+
8
+ /**
9
+ * JAKU-API — API & Auth Flow Verification Agent
10
+ *
11
+ * Pipeline:
12
+ * 1. Test authentication flows (JWT, sessions, passwords, MFA)
13
+ * 2. Probe OAuth/SSO security
14
+ * 3. Audit API key management
15
+ * 4. Test GraphQL-specific vulnerabilities
16
+ * 5. Validate CORS and WebSocket security
17
+ *
18
+ * Dependencies: JAKU-CRAWL (runs in Wave 2, parallel with QA + SEC + AI + LOGIC)
19
+ */
20
+ export class APIAgent extends BaseAgent {
21
+ get name() { return 'JAKU-API'; }
22
+ get dependencies() { return ['JAKU-CRAWL']; }
23
+
24
+ async _execute(context) {
25
+ const { config, logger, surfaceInventory } = context;
26
+
27
+ if (!surfaceInventory) {
28
+ throw new Error('No surface inventory available — JAKU-CRAWL must run first');
29
+ }
30
+
31
+ // Phase 1: Auth flow testing
32
+ this.progress('auth', 'Testing authentication flows...', 0);
33
+ try {
34
+ const authTester = new AuthFlowTester(logger);
35
+ const authFindings = await authTester.test(surfaceInventory);
36
+ this.addFindings(authFindings);
37
+ this._log(`Auth flows: ${authFindings.length} issues`);
38
+ } catch (err) {
39
+ this._log(`Auth flow testing failed: ${err.message}`, 'error');
40
+ }
41
+ this.progress('auth', 'Auth flow testing complete', 20);
42
+
43
+ // Phase 2: OAuth probing
44
+ this.progress('oauth', 'Probing OAuth/SSO flows...', 20);
45
+ try {
46
+ const oauthProber = new OAuthProber(logger);
47
+ const oauthFindings = await oauthProber.probe(surfaceInventory);
48
+ this.addFindings(oauthFindings);
49
+ this._log(`OAuth: ${oauthFindings.length} issues`);
50
+ } catch (err) {
51
+ this._log(`OAuth probing failed: ${err.message}`, 'error');
52
+ }
53
+ this.progress('oauth', 'OAuth probing complete', 40);
54
+
55
+ // Phase 3: API key audit
56
+ this.progress('apikeys', 'Auditing API key management...', 40);
57
+ try {
58
+ const keyAuditor = new APIKeyAuditor(logger);
59
+ const keyFindings = await keyAuditor.audit(surfaceInventory);
60
+ this.addFindings(keyFindings);
61
+ this._log(`API keys: ${keyFindings.length} issues`);
62
+ } catch (err) {
63
+ this._log(`API key audit failed: ${err.message}`, 'error');
64
+ }
65
+ this.progress('apikeys', 'API key audit complete', 60);
66
+
67
+ // Phase 4: GraphQL testing
68
+ this.progress('graphql', 'Testing GraphQL endpoints...', 60);
69
+ try {
70
+ const gqlTester = new GraphQLTester(logger);
71
+ const gqlFindings = await gqlTester.test(surfaceInventory);
72
+ this.addFindings(gqlFindings);
73
+ this._log(`GraphQL: ${gqlFindings.length} issues`);
74
+ } catch (err) {
75
+ this._log(`GraphQL testing failed: ${err.message}`, 'error');
76
+ }
77
+ this.progress('graphql', 'GraphQL testing complete', 80);
78
+
79
+ // Phase 5: CORS & WebSocket testing
80
+ this.progress('cors-ws', 'Testing CORS and WebSocket security...', 80);
81
+ try {
82
+ const corsTester = new CORSWSTester(logger);
83
+ const corsFindings = await corsTester.test(surfaceInventory);
84
+ this.addFindings(corsFindings);
85
+ this._log(`CORS/WS: ${corsFindings.length} issues`);
86
+ } catch (err) {
87
+ this._log(`CORS/WS testing failed: ${err.message}`, 'error');
88
+ }
89
+ this.progress('cors-ws', 'CORS/WS testing complete', 100);
90
+
91
+ this.progress('complete', `API scan complete — ${this._findings.length} total findings`, 100);
92
+ }
93
+ }
94
+
95
+ export default APIAgent;