jaku.sh 1.0.3 → 1.2.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.
- package/README.md +218 -18
- package/action.yml +32 -1
- package/package.json +6 -5
- package/scripts/postinstall.js +73 -0
- package/src/agents/ai-agent.js +47 -1
- package/src/agents/api-agent.js +9 -0
- package/src/agents/logic-agent.js +158 -90
- package/src/agents/orchestrator.js +56 -1
- package/src/agents/security-agent.js +86 -54
- package/src/cli.js +79 -6
- package/src/core/ai/ai-endpoint-detector.js +28 -4
- package/src/core/ai/prompt-injector.js +34 -0
- package/src/core/api/api-key-auditor.js +1 -1
- package/src/core/api/cors-ws-tester.js +1 -1
- package/src/core/llm/augmentations.js +210 -0
- package/src/core/llm/llm-client.js +184 -0
- package/src/core/llm/providers/anthropic-provider.js +46 -0
- package/src/core/llm/providers/base-provider.js +44 -0
- package/src/core/llm/providers/null-provider.js +21 -0
- package/src/core/llm/providers/openai-provider.js +47 -0
- package/src/core/logic/access-boundary-tester.js +1 -1
- package/src/core/logic/business-rule-inferrer.js +50 -1
- package/src/core/security/sqli-prober.js +312 -43
- package/src/core/security/xss-scanner.js +26 -2
- package/src/reporting/report-generator.js +96 -9
- package/src/reporting/sarif-generator.js +81 -5
- package/src/utils/browser.js +62 -0
- package/src/utils/config.js +196 -2
- package/src/utils/finding.js +3 -0
- package/src/utils/logger.js +33 -0
- package/src/utils/param-discovery.js +93 -0
- package/src/utils/safety.js +44 -0
- package/src/utils/version.js +30 -0
package/README.md
CHANGED
|
@@ -11,12 +11,17 @@ JAKU crawls your entire app, generates test cases, probes for security vulnerabi
|
|
|
11
11
|
## Table of Contents
|
|
12
12
|
|
|
13
13
|
- [Quick Start](#quick-start)
|
|
14
|
+
- [Updating](#updating)
|
|
14
15
|
- [Architecture](#architecture)
|
|
15
16
|
- [Module 01 — QA & Functional Testing](#module-01--qa--functional-testing)
|
|
16
17
|
- [Module 02 — Security Vulnerability Scanning](#module-02--security-vulnerability-scanning)
|
|
18
|
+
- [Module 03 — Business Logic Validation](#module-03--business-logic-validation)
|
|
17
19
|
- [Module 04 — Prompt Injection & AI Abuse Detection](#module-04--prompt-injection--ai-abuse-detection)
|
|
20
|
+
- [Module 05 — API & Auth Flow Verification](#module-05--api--auth-flow-verification)
|
|
18
21
|
- [Correlation Engine](#correlation-engine)
|
|
19
22
|
- [CLI Reference](#cli-reference)
|
|
23
|
+
- [Safety Modes](#safety-modes)
|
|
24
|
+
- [LLM Augmentation (optional)](#llm-augmentation-optional)
|
|
20
25
|
- [Reports](#reports)
|
|
21
26
|
- [Severity Framework](#severity-framework)
|
|
22
27
|
- [Configuration](#configuration)
|
|
@@ -68,6 +73,62 @@ node src/cli.js security https://your-app.dev --severity high
|
|
|
68
73
|
|
|
69
74
|
---
|
|
70
75
|
|
|
76
|
+
## Updating
|
|
77
|
+
|
|
78
|
+
Already running JAKU? Update to the latest release:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Global install (most common)
|
|
82
|
+
npm install -g jaku.sh@latest
|
|
83
|
+
jaku --version # confirm you're on the latest
|
|
84
|
+
|
|
85
|
+
# Refresh the browser engine if the post-install step was skipped
|
|
86
|
+
npx playwright install chromium
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# npx users — pin @latest so a stale cached copy isn't reused
|
|
91
|
+
npx jaku.sh@latest scan https://your-app.dev --prod-safe
|
|
92
|
+
|
|
93
|
+
# Project dependency
|
|
94
|
+
npm install -D jaku.sh@latest
|
|
95
|
+
|
|
96
|
+
# GitHub Action — pin to the release tag
|
|
97
|
+
# - uses: theshantanupandey/jaku@v1.2.0
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### What's new in v1.2.1
|
|
101
|
+
|
|
102
|
+
- **Resilient install.** The Chromium download no longer blocks or breaks
|
|
103
|
+
`npm install` — it is non-fatal, interrupt-safe (a Ctrl+C won't fail the
|
|
104
|
+
install), and skippable with `JAKU_SKIP_BROWSER_DOWNLOAD=1`.
|
|
105
|
+
- **Auto browser setup on first scan.** If Chromium is missing when you run a
|
|
106
|
+
scan, JAKU installs it automatically (one-time) instead of erroring out.
|
|
107
|
+
|
|
108
|
+
> Updating? If a previous Chromium download was interrupted, just run a scan —
|
|
109
|
+
> JAKU will finish setting up the browser — or run `npx playwright install chromium`.
|
|
110
|
+
|
|
111
|
+
### What's new in v1.2.0
|
|
112
|
+
|
|
113
|
+
> ⚠ **Behavior change for existing users:** destructive business-logic tests
|
|
114
|
+
> (race conditions, pricing/checkout mutation, etc.) are now **gated behind
|
|
115
|
+
> `--aggressive`** and **skipped by default**. A plain `jaku scan` is now safer
|
|
116
|
+
> than before — if you relied on those tests running by default, add
|
|
117
|
+
> `--aggressive`. Everything else is additive and backward-compatible.
|
|
118
|
+
|
|
119
|
+
| Area | Change |
|
|
120
|
+
|------|--------|
|
|
121
|
+
| **Safety modes** | New `--passive` / `--safe-active` (default) / `--aggressive` tiers; destructive tests gated to `--aggressive` |
|
|
122
|
+
| **AI testing fix** | AI endpoint detection now works on JSON/API chat endpoints (previously skipped silently) |
|
|
123
|
+
| **LLM augmentation** | Optional, bring-your-own-key AI assistance — remediation, exec summaries, tailored payloads, FP triage. Off by default, no new dependencies — see [LLM Augmentation](#llm-augmentation-optional) |
|
|
124
|
+
| **Deeper scanning** | Real parameter discovery for XSS/SQLi + boolean-based and time-based **blind SQLi** detection |
|
|
125
|
+
| **Better outputs** | Reports reflect the actual modules that ran; SARIF adds `partialFingerprints` + proper web URIs for cross-run tracking |
|
|
126
|
+
| **Config & safety** | Lightweight config validation with warnings; API keys rejected from config files; version centralized |
|
|
127
|
+
|
|
128
|
+
Full file-level history is on [GitHub](https://github.com/theshantanupandey/jaku/commits/main).
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
71
132
|
## Architecture
|
|
72
133
|
|
|
73
134
|
JAKU is a **multi-agent system** — a central Orchestrator coordinates 6 specialized sub-agents that run in parallel, sharing discoveries through an event-driven message bus and a unified findings ledger with attack chain correlation.
|
|
@@ -78,7 +139,7 @@ JAKU is a **multi-agent system** — a central Orchestrator coordinates 6 specia
|
|
|
78
139
|
|-------|------|-------------|---------|
|
|
79
140
|
| **JAKU-CRAWL** | Surface discovery | — | Wave 1 (solo) |
|
|
80
141
|
| **JAKU-QA** | QA & functional testing (5 sub-modules) | JAKU-CRAWL | Wave 2 (parallel) |
|
|
81
|
-
| **JAKU-SEC** | Security vulnerability scanning (
|
|
142
|
+
| **JAKU-SEC** | Security vulnerability scanning (15 sub-modules) | JAKU-CRAWL | Wave 2 (parallel) |
|
|
82
143
|
| **JAKU-AI** | Prompt injection & AI abuse (8 sub-modules) | JAKU-CRAWL | Wave 2 (parallel) |
|
|
83
144
|
| **JAKU-LOGIC** | Business logic validation (6 sub-modules) | JAKU-CRAWL | Wave 2 (parallel) |
|
|
84
145
|
| **JAKU-API** | API & auth flow verification (5 sub-modules) | JAKU-CRAWL | Wave 2 (parallel) |
|
|
@@ -213,19 +274,34 @@ node src/cli.js qa https://your-app.dev --verbose
|
|
|
213
274
|
|
|
214
275
|
## Module 02 — Security Vulnerability Scanning
|
|
215
276
|
|
|
216
|
-
Probes your app's attack surface
|
|
277
|
+
Probes your app's attack surface. Under the default `--safe-active` mode these
|
|
278
|
+
checks use detection-only payloads and do not issue state-changing requests
|
|
279
|
+
(see [Safety Modes](#safety-modes)).
|
|
217
280
|
|
|
218
281
|
| Sub-Module | What It Does |
|
|
219
282
|
|-----------|-------------|
|
|
220
283
|
| **Header Analyzer** | Checks CSP, HSTS, X-Frame-Options, X-Content-Type-Options, CORS, Referrer-Policy, Permissions-Policy, and technology fingerprinting |
|
|
221
284
|
| **Secret Detector** | Scans page source, JS, and inline scripts for 19 secret patterns (AWS, Google, Stripe, GitHub, Slack, Firebase, JWT, DB URLs, private keys). Probes 21 sensitive paths (`.env`, `.git/config`, `/debug`, `/actuator`). Checks for source map exposure |
|
|
222
|
-
| **XSS Scanner** | Tests URL parameters and form inputs for reflected and stored XSS using 9 detection-only payloads |
|
|
223
|
-
| **SQLi Prober** | Tests URL params, form inputs, and API endpoints with
|
|
285
|
+
| **XSS Scanner** | Tests URL parameters and form inputs for reflected and stored XSS using 9 detection-only payloads (parameters are discovered from forms/links/APIs, with a fallback name list) |
|
|
286
|
+
| **SQLi Prober** | Tests URL params, form inputs, and API endpoints with SQL and NoSQL payloads. Detects 18 database error signatures plus boolean-based and time-based blind injection |
|
|
224
287
|
| **Dependency Auditor** | Runs `npm audit`, maps CVE advisories to JAKU severity, checks for unpinned dependencies and risky npm scripts |
|
|
225
288
|
| **TLS Checker** | Validates certificate expiry, detects self-signed certs, checks HTTP→HTTPS redirect, and scans for mixed content |
|
|
226
289
|
| **Infrastructure Scanner** | Probes 40 admin/debug endpoints, detects directory listing, checks error pages for information disclosure, and tests GraphQL introspection |
|
|
227
|
-
|
|
228
|
-
|
|
290
|
+
| **File Upload Tester** | Tests upload endpoints for MIME spoofing, dangerous extensions, and path traversal *(active — `safe-active`+)* |
|
|
291
|
+
| **CSRF Detector** | Checks state-changing forms/endpoints for anti-CSRF tokens and SameSite cookie protection |
|
|
292
|
+
| **Open Redirect Detector** | Tests redirect parameters for unvalidated off-site redirection *(active — `safe-active`+)* |
|
|
293
|
+
| **Subdomain Scanner** | Enumerates common subdomains and flags exposed/sensitive hosts |
|
|
294
|
+
| **Cookie Auditor** | Audits cookies for `HttpOnly`, `Secure`, `SameSite`, and scope/expiry hygiene |
|
|
295
|
+
| **CSP Validator** | Parses Content-Security-Policy for unsafe directives (`unsafe-inline`, `unsafe-eval`, wildcards, missing directives) |
|
|
296
|
+
| **Clickjacking Detector** | Verifies frame-busting protection via `X-Frame-Options` / CSP `frame-ancestors` |
|
|
297
|
+
| **SSRF Prober** | Probes server-side request forgery via URL/host parameters *(active — `safe-active`+)* |
|
|
298
|
+
|
|
299
|
+
> **Safety:** Module 02 (security) checks use detection-only payloads and do not
|
|
300
|
+
> perform destructive operations in any mode. Note that some **Module 03
|
|
301
|
+
> (business logic)** tests *do* send real state-changing requests (e.g. race
|
|
302
|
+
> conditions, pricing/checkout mutation) — those are gated behind the
|
|
303
|
+
> `--aggressive` safety mode and are **skipped by default**. See
|
|
304
|
+
> [Safety Modes](#safety-modes).
|
|
229
305
|
|
|
230
306
|
```bash
|
|
231
307
|
# Security only
|
|
@@ -238,6 +314,12 @@ node src/cli.js security https://your-app.dev --verbose
|
|
|
238
314
|
|
|
239
315
|
Detects business logic flaws that traditional scanners miss: pricing manipulation, access control bypass, workflow skipping, race conditions, and referral abuse.
|
|
240
316
|
|
|
317
|
+
> ⚠ **Some logic tests are destructive.** Pricing exploitation, race-condition,
|
|
318
|
+
> cart-manipulation, coupon-abuse, and account-takeover testing issue (or are
|
|
319
|
+
> classified as) real state-changing requests. They only run under
|
|
320
|
+
> `--aggressive` and are **skipped by default** (`--safe-active`). See
|
|
321
|
+
> [Safety Modes](#safety-modes).
|
|
322
|
+
|
|
241
323
|
### How It Works
|
|
242
324
|
|
|
243
325
|
Unlike security scanning, business logic testing requires **understanding what the app does**. JAKU-LOGIC first infers business rules from your app's surface:
|
|
@@ -288,6 +370,11 @@ node src/cli.js scan https://your-app.dev --modules security,logic
|
|
|
288
370
|
| 3 | **System Prompt Extractor** | 17 techniques | Direct repeat, token forcing ("Continue: You are a"), structured output (JSON/YAML), indirect summarization, fill-in-the-blanks, reverse output |
|
|
289
371
|
| 4 | **Output Analyzer** | 10 tests | AI-mediated XSS: makes the AI generate `<script>` tags, `<img onerror>`, SVG onload, markdown `javascript:` links, data exfiltration payloads — tests if output is rendered unsanitized |
|
|
290
372
|
| 5 | **Guardrail Prober** | 15 probes | PII leakage (other users' data), excessive agency (delete account, send emails, execute code), off-topic compliance, tool/function-call abuse |
|
|
373
|
+
| 6 | **Model DoS Tester** | resource probes | Context bombing, token-loop / repetition attacks, and oversized-input handling to detect denial-of-wallet / resource exhaustion |
|
|
374
|
+
| 7 | **Indirect Injector** | 6 payloads | Indirect prompt injection via content the AI later ingests (e.g. retrieved/stored data, profile fields) rather than the direct chat input |
|
|
375
|
+
|
|
376
|
+
> Detection runs first via the **AI Endpoint Detector**, then the 7 phases above
|
|
377
|
+
> run against each detected endpoint — 8 AI sub-modules in total.
|
|
291
378
|
|
|
292
379
|
### AI Threat Categories
|
|
293
380
|
|
|
@@ -417,10 +504,103 @@ Correlations appear in the CLI output and reports with severity escalation.
|
|
|
417
504
|
| `--halt-on-critical` | Abort scan immediately on any critical finding | off |
|
|
418
505
|
| `--webhook <url>` | POST findings summary to webhook URL on completion | off |
|
|
419
506
|
| `--prod-safe` | Confirm authorization to scan production targets | off |
|
|
507
|
+
| `--passive` | Safety mode: recon + static analysis only (no attack probing) | — |
|
|
508
|
+
| `--safe-active` | Safety mode: non-destructive active probing | **default** |
|
|
509
|
+
| `--aggressive` | Safety mode: enable destructive/state-changing tests | — |
|
|
510
|
+
| `--llm` | Enable optional LLM augmentation (key from env) | off |
|
|
511
|
+
| `--llm-provider <name>` | LLM provider: `openai` or `anthropic` | `openai` |
|
|
512
|
+
| `--llm-model <id>` | LLM model id | provider default |
|
|
513
|
+
| `--llm-consent` | Consent to send minimal finding/target data to the provider | off |
|
|
420
514
|
| `--json` | Output JSON report | off |
|
|
421
515
|
| `--html` | Output HTML report | off |
|
|
422
516
|
| `-v, --verbose` | Enable verbose logging | off |
|
|
423
517
|
|
|
518
|
+
### Safety Modes
|
|
519
|
+
|
|
520
|
+
JAKU exposes three explicit safety tiers so you control how invasive a scan is.
|
|
521
|
+
The default is `--safe-active`. You can also set `"safety_mode"` in
|
|
522
|
+
`jaku.config.json`; the CLI flag takes precedence.
|
|
523
|
+
|
|
524
|
+
| Mode | Flag | What runs | What it never does |
|
|
525
|
+
|------|------|-----------|--------------------|
|
|
526
|
+
| **Passive** | `--passive` | Crawl/discovery + read-only/static analysis only (headers, secrets, TLS, cookies, CSP, clickjacking, static form/API analysis) | Sends no attack payloads and no state-changing requests. Active probers (XSS, SQLi, infra, SSRF, file-upload, open-redirect, AI, API/auth, and all logic tests) are skipped. |
|
|
527
|
+
| **Safe-Active** *(default)* | `--safe-active` | Everything in passive **plus** non-destructive active probing: XSS/SQLi probes, AI prompt-injection, API/auth verification, and non-destructive logic checks (access boundary, workflow, abuse patterns, email enumeration, feature flags) | Never issues destructive/state-changing requests. Destructive logic tests are skipped with a clear log line. |
|
|
528
|
+
| **Aggressive** | `--aggressive` | Everything in safe-active **plus** destructive/state-changing tests: pricing exploitation, race conditions, cart manipulation, coupon abuse, account takeover | — (use only against environments you are authorized to mutate) |
|
|
529
|
+
|
|
530
|
+
> JAKU is a security scanner and **intentionally does not honor `robots.txt`** in
|
|
531
|
+
> any mode. The legacy `respect_robots` / `respect_robots_txt` config key has
|
|
532
|
+
> been removed.
|
|
533
|
+
|
|
534
|
+
### LLM Augmentation (optional)
|
|
535
|
+
|
|
536
|
+
JAKU can optionally use your **own** LLM API key to make scans smarter. This
|
|
537
|
+
feature is **off by default and strictly additive** — with no key, no `--llm`
|
|
538
|
+
flag, no consent, an unreachable API, or an exhausted budget, JAKU behaves
|
|
539
|
+
**exactly** as it does without it. The LLM **never** decides core pass/fail;
|
|
540
|
+
deterministic scanners always own the verdict.
|
|
541
|
+
|
|
542
|
+
**What the LLM adds (all advisory / tagged `source: "llm"`):**
|
|
543
|
+
|
|
544
|
+
| Phase | Augmentation | Where |
|
|
545
|
+
|-------|--------------|-------|
|
|
546
|
+
| 0 | Framework-specific remediation guidance + executive summary | reports |
|
|
547
|
+
| 1 | Context-aware prompt-injection payloads tailored to a leaked system prompt | `JAKU-AI` |
|
|
548
|
+
| 2 | False-positive triage of borderline findings + attack-chain narrative enrichment | synthesis + reports |
|
|
549
|
+
| 3 | Extra business-domain / invariant inference | `JAKU-LOGIC` |
|
|
550
|
+
|
|
551
|
+
**Enabling it:**
|
|
552
|
+
|
|
553
|
+
```bash
|
|
554
|
+
# Key comes ONLY from the environment — never the config file or CLI
|
|
555
|
+
export OPENAI_API_KEY=sk-... # or ANTHROPIC_API_KEY=sk-ant-...
|
|
556
|
+
|
|
557
|
+
node src/cli.js scan https://myapp.dev --llm --llm-consent --llm-provider openai
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
Both `--llm` (enablement) **and** `--llm-consent` (or `llm.consent: true`) are
|
|
561
|
+
required before any data leaves your machine. Configure non-secret settings in
|
|
562
|
+
`jaku.config.json`:
|
|
563
|
+
|
|
564
|
+
```jsonc
|
|
565
|
+
"llm": {
|
|
566
|
+
"enabled": false, // or pass --llm
|
|
567
|
+
"provider": "openai", // openai | anthropic
|
|
568
|
+
"model": null, // null → cheap provider default
|
|
569
|
+
"max_tokens": 1024, // per-call output cap
|
|
570
|
+
"max_calls": 50, // per-scan call budget
|
|
571
|
+
"token_budget": 100000, // per-scan token budget
|
|
572
|
+
"timeout_seconds": 30,
|
|
573
|
+
"consent": false, // or pass --llm-consent
|
|
574
|
+
"base_url": null // optional self-hosted/proxy endpoint
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
**What data leaves the machine (data minimization):**
|
|
579
|
+
|
|
580
|
+
- *Remediation:* finding title, module, severity, description.
|
|
581
|
+
- *Triage:* title, severity, description, a short evidence snippet — borderline findings only.
|
|
582
|
+
- *Executive summary:* severity counts + finding **titles** (no bodies/evidence).
|
|
583
|
+
- *Payload generation:* a snippet of the **already-leaked** system prompt + the target host.
|
|
584
|
+
- *Business inference:* discovered URL **paths** + form field **names** (no values, no bodies).
|
|
585
|
+
|
|
586
|
+
**Security & safety guarantees:**
|
|
587
|
+
|
|
588
|
+
- **Keys never persist or print.** The API key is read from the environment only,
|
|
589
|
+
is never written to config, logs, reports, `meta`, `finding.evidence`, or PR
|
|
590
|
+
comments. The logger scrubs `sk-…`, `Bearer …`, and `x-api-key` patterns from
|
|
591
|
+
all output. Putting an `api_key` in `jaku.config.json` is rejected with a warning.
|
|
592
|
+
- **Passive mode = no egress.** Third-party calls are auto-disabled in `--passive`.
|
|
593
|
+
- **Safety-tier gating.** LLM-generated **destructive** payloads only fire under
|
|
594
|
+
`--aggressive`; non-destructive generated probes require `--safe-active`.
|
|
595
|
+
- **Budgeted & resilient.** Per-scan call/token budgets, per-call timeout,
|
|
596
|
+
429 backoff, and a connection-failure circuit breaker — any failure degrades
|
|
597
|
+
silently to deterministic behavior.
|
|
598
|
+
- **No new dependencies.** Uses the built-in `fetch` only.
|
|
599
|
+
|
|
600
|
+
To disable, simply omit `--llm` (or set `"enabled": false`). In CI, set
|
|
601
|
+
`enable-llm: 'true'` on the action and provide `OPENAI_API_KEY` /
|
|
602
|
+
`ANTHROPIC_API_KEY` from repository secrets in the job environment.
|
|
603
|
+
|
|
424
604
|
### Report Formats
|
|
425
605
|
|
|
426
606
|
Every scan generates 5 report files:
|
|
@@ -467,12 +647,14 @@ node src/cli.js ai https://myapp.dev/api/chat --max-pages 1 -v
|
|
|
467
647
|
```
|
|
468
648
|
╦╔═╗╦╔═╦ ╦
|
|
469
649
|
║╠═╣╠╩╗║ ║ 呪 Autonomous Security & Quality Intelligence
|
|
470
|
-
╚╝╩ ╩╩ ╩╚═╝ v1.0
|
|
650
|
+
╚╝╩ ╩╩ ╩╚═╝ v1.2.0 · Multi-Agent
|
|
471
651
|
|
|
472
652
|
Target: https://your-app.dev
|
|
473
653
|
Modules: QA + SECURITY + AI
|
|
474
654
|
Mode: Multi-Agent Orchestration
|
|
655
|
+
Safety: Safe-Active (non-destructive probing)
|
|
475
656
|
Severity: ≥ low
|
|
657
|
+
LLM: disabled — not enabled (set llm.enabled or pass --llm)
|
|
476
658
|
|
|
477
659
|
✔ [JAKU-CRAWL] Complete — 0 findings in 2.1s
|
|
478
660
|
✔ [JAKU-QA] Complete — 3 findings in 14.9s ⚡parallel
|
|
@@ -505,13 +687,16 @@ node src/cli.js ai https://myapp.dev/api/chat --max-pages 1 -v
|
|
|
505
687
|
|
|
506
688
|
## Reports
|
|
507
689
|
|
|
508
|
-
Every scan generates
|
|
690
|
+
Every scan generates the following report formats, saved to `jaku-reports/<timestamp>/`:
|
|
509
691
|
|
|
510
692
|
| Format | File | Description |
|
|
511
693
|
|--------|------|-------------|
|
|
512
694
|
| **JSON** | `report.json` | Machine-readable findings array for CI/CD integration |
|
|
513
695
|
| **Markdown** | `report.md` | Human-readable narrative with severity tables and finding details |
|
|
514
696
|
| **HTML** | `report.html` | Self-contained dark-themed report with severity charts, filters, and embedded evidence |
|
|
697
|
+
| **SARIF** | `report.sarif` | GitHub/GitLab Security Dashboard integration (SARIF v2.1.0) |
|
|
698
|
+
| **Diff** | `diff-report.md` / `diff-report.json` | Regression detection vs. the previous scan run |
|
|
699
|
+
| **OWASP Compliance** | `compliance-owasp.*` | OWASP Top 10 pass/fail report (JSON + MD + HTML) — only with `--compliance owasp` |
|
|
515
700
|
|
|
516
701
|
### Finding Schema
|
|
517
702
|
|
|
@@ -536,7 +721,7 @@ Every scan generates three report formats, saved to `jaku-reports/<timestamp>/`:
|
|
|
536
721
|
}
|
|
537
722
|
```
|
|
538
723
|
|
|
539
|
-
Modules tag findings as: `qa`, `security`, or `
|
|
724
|
+
Modules tag findings as: `qa`, `security`, `ai`, `logic`, or `api`.
|
|
540
725
|
|
|
541
726
|
---
|
|
542
727
|
|
|
@@ -563,33 +748,48 @@ cp jaku.config.example.json jaku.config.json
|
|
|
563
748
|
```json
|
|
564
749
|
{
|
|
565
750
|
"target_url": "https://your-app.dev",
|
|
566
|
-
"
|
|
567
|
-
"username": "",
|
|
568
|
-
"password": ""
|
|
569
|
-
},
|
|
570
|
-
"modules": ["qa", "security", "ai"],
|
|
751
|
+
"modules_enabled": ["qa", "security", "ai", "logic", "api"],
|
|
571
752
|
"severity_threshold": "low",
|
|
753
|
+
"safety_mode": "safe-active",
|
|
572
754
|
"halt_on_critical": true,
|
|
573
755
|
"crawler": {
|
|
574
756
|
"max_pages": 50,
|
|
575
757
|
"max_depth": 5,
|
|
576
|
-
"
|
|
758
|
+
"concurrency": 4
|
|
759
|
+
},
|
|
760
|
+
"llm": {
|
|
761
|
+
"enabled": false,
|
|
762
|
+
"provider": "openai",
|
|
763
|
+
"consent": false
|
|
577
764
|
}
|
|
578
765
|
}
|
|
579
766
|
```
|
|
580
767
|
|
|
768
|
+
> The LLM API key is **never** stored in this file — it is read from the
|
|
769
|
+
> `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` environment variable only. See
|
|
770
|
+
> [LLM Augmentation](#llm-augmentation-optional).
|
|
771
|
+
|
|
772
|
+
Unknown, mistyped, or deprecated keys in `jaku.config.json` are reported as
|
|
773
|
+
warnings on load (and ignored) rather than silently honored.
|
|
774
|
+
|
|
581
775
|
### Configuration Options
|
|
582
776
|
|
|
583
777
|
| Key | Type | Description |
|
|
584
778
|
|-----|------|-------------|
|
|
585
779
|
| `target_url` | string | The application URL to scan |
|
|
586
|
-
| `credentials` | object | Login credentials for authenticated scanning |
|
|
587
|
-
| `
|
|
780
|
+
| `credentials` | object[] | Login credentials for authenticated scanning |
|
|
781
|
+
| `modules_enabled` | string[] | Modules to enable: `qa`, `security`, `ai`, `logic`, `api` |
|
|
588
782
|
| `severity_threshold` | string | Minimum severity to report: `critical`, `high`, `medium`, `low` |
|
|
783
|
+
| `safety_mode` | string | Safety tier: `passive`, `safe-active` (default), `aggressive` — see [Safety Modes](#safety-modes) |
|
|
589
784
|
| `halt_on_critical` | boolean | Exit with code 1 if critical findings detected (for CI/CD) |
|
|
590
785
|
| `crawler.max_pages` | number | Maximum pages to crawl |
|
|
591
786
|
| `crawler.max_depth` | number | Maximum link depth to follow |
|
|
592
|
-
| `crawler.
|
|
787
|
+
| `crawler.concurrency` | number | Parallel crawl workers |
|
|
788
|
+
| `llm.enabled` | boolean | Enable optional LLM augmentation (default `false`) — see [LLM Augmentation](#llm-augmentation-optional) |
|
|
789
|
+
| `llm.provider` | string | `openai` or `anthropic` |
|
|
790
|
+
| `llm.model` | string | Model id (provider default if omitted) |
|
|
791
|
+
| `llm.consent` | boolean | Required (with enablement) before any data egress |
|
|
792
|
+
| `llm.max_calls` / `llm.token_budget` | number | Per-scan call / token budgets |
|
|
593
793
|
|
|
594
794
|
### CI/CD Integration
|
|
595
795
|
|
package/action.yml
CHANGED
|
@@ -49,6 +49,18 @@ inputs:
|
|
|
49
49
|
description: 'Maximum pages to crawl'
|
|
50
50
|
required: false
|
|
51
51
|
default: '50'
|
|
52
|
+
enable-llm:
|
|
53
|
+
description: 'Enable optional LLM augmentation (requires OPENAI_API_KEY or ANTHROPIC_API_KEY in job env and consent)'
|
|
54
|
+
required: false
|
|
55
|
+
default: 'false'
|
|
56
|
+
llm-provider:
|
|
57
|
+
description: 'LLM provider when enabled (openai|anthropic)'
|
|
58
|
+
required: false
|
|
59
|
+
default: 'openai'
|
|
60
|
+
llm-model:
|
|
61
|
+
description: 'LLM model id (provider default if empty)'
|
|
62
|
+
required: false
|
|
63
|
+
default: ''
|
|
52
64
|
verbose:
|
|
53
65
|
description: 'Enable verbose logging'
|
|
54
66
|
required: false
|
|
@@ -102,6 +114,14 @@ runs:
|
|
|
102
114
|
JAKU_AUTH_STRATEGY: ${{ inputs.auth-strategy }}
|
|
103
115
|
JAKU_MAX_PAGES: ${{ inputs.max-pages }}
|
|
104
116
|
JAKU_VERBOSE: ${{ inputs.verbose }}
|
|
117
|
+
JAKU_ENABLE_LLM: ${{ inputs.enable-llm }}
|
|
118
|
+
JAKU_LLM_PROVIDER: ${{ inputs.llm-provider }}
|
|
119
|
+
JAKU_LLM_MODEL: ${{ inputs.llm-model }}
|
|
120
|
+
# API keys are read from the job environment (set these from repo secrets
|
|
121
|
+
# in your workflow, e.g. OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}).
|
|
122
|
+
# They are passed to the scanner process only and never printed.
|
|
123
|
+
OPENAI_API_KEY: ${{ env.OPENAI_API_KEY }}
|
|
124
|
+
ANTHROPIC_API_KEY: ${{ env.ANTHROPIC_API_KEY }}
|
|
105
125
|
run: |
|
|
106
126
|
REPORT_DIR="${{ runner.temp }}/jaku-reports"
|
|
107
127
|
|
|
@@ -124,6 +144,17 @@ runs:
|
|
|
124
144
|
if [ "${JAKU_VERBOSE}" = "true" ]; then
|
|
125
145
|
CMD="${CMD} --verbose"
|
|
126
146
|
fi
|
|
147
|
+
|
|
148
|
+
# Optional LLM augmentation. Only enabled when explicitly requested AND a
|
|
149
|
+
# key is present in the environment. The key itself is never added to the
|
|
150
|
+
# command line — LLMClient reads it from env. --llm-consent is implied by
|
|
151
|
+
# the operator opting in via enable-llm in CI.
|
|
152
|
+
if [ "${JAKU_ENABLE_LLM}" = "true" ] && { [ -n "${OPENAI_API_KEY}" ] || [ -n "${ANTHROPIC_API_KEY}" ]; }; then
|
|
153
|
+
CMD="${CMD} --llm --llm-consent --llm-provider ${JAKU_LLM_PROVIDER}"
|
|
154
|
+
if [ -n "${JAKU_LLM_MODEL}" ]; then
|
|
155
|
+
CMD="${CMD} --llm-model ${JAKU_LLM_MODEL}"
|
|
156
|
+
fi
|
|
157
|
+
fi
|
|
127
158
|
|
|
128
159
|
# Run scan
|
|
129
160
|
eval ${CMD} || true
|
|
@@ -217,7 +248,7 @@ runs:
|
|
|
217
248
|
}
|
|
218
249
|
}
|
|
219
250
|
|
|
220
|
-
body +=
|
|
251
|
+
body += `\n---\n*Scanned by [JAKU](https://github.com/jaku-security/jaku) v${report.meta?.version || ''}*`;
|
|
221
252
|
} else {
|
|
222
253
|
body += '⚠️ Scan completed but no report was generated. Check workflow logs for errors.';
|
|
223
254
|
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jaku.sh",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.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",
|
|
7
7
|
"bin": {
|
|
8
|
-
"jaku": "
|
|
8
|
+
"jaku": "bin/jaku"
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=20"
|
|
@@ -13,12 +13,13 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"src/",
|
|
15
15
|
"bin/",
|
|
16
|
+
"scripts/",
|
|
16
17
|
"action.yml",
|
|
17
18
|
"README.md"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"scan": "node src/cli.js scan",
|
|
21
|
-
"postinstall": "
|
|
22
|
+
"postinstall": "node scripts/postinstall.js",
|
|
22
23
|
"prepublishOnly": "node src/cli.js --help"
|
|
23
24
|
},
|
|
24
25
|
"keywords": [
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"homepage": "https://jaku.app",
|
|
47
48
|
"repository": {
|
|
48
49
|
"type": "git",
|
|
49
|
-
"url": "https://github.com/theshantanupandey/jaku.git"
|
|
50
|
+
"url": "git+https://github.com/theshantanupandey/jaku.git"
|
|
50
51
|
},
|
|
51
52
|
"bugs": {
|
|
52
53
|
"url": "https://github.com/theshantanupandey/jaku/issues"
|
|
@@ -59,4 +60,4 @@
|
|
|
59
60
|
"playwright": "^1.49.1",
|
|
60
61
|
"winston": "^3.17.0"
|
|
61
62
|
}
|
|
62
|
-
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* JAKU postinstall — installs the Chromium build Playwright needs.
|
|
4
|
+
*
|
|
5
|
+
* Design goals (it must NEVER break `npm install`):
|
|
6
|
+
* - Skippable via JAKU_SKIP_BROWSER_DOWNLOAD / PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD.
|
|
7
|
+
* - Non-fatal: any failure (network, missing npx, etc.) exits 0 with guidance.
|
|
8
|
+
* - Interrupt-safe: a Ctrl+C (SIGINT) during the ~170 MB download leaves the
|
|
9
|
+
* CLI installed and exits 0 instead of failing the whole install. JAKU will
|
|
10
|
+
* auto-install the browser on first scan if it is still missing.
|
|
11
|
+
*/
|
|
12
|
+
import { spawnSync } from 'node:child_process';
|
|
13
|
+
|
|
14
|
+
function log(msg) {
|
|
15
|
+
process.stdout.write(`${msg}\n`);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const MANUAL = 'Run `npx playwright install chromium` before your first scan.';
|
|
19
|
+
|
|
20
|
+
// If interrupted directly, don't fail the install.
|
|
21
|
+
process.on('SIGINT', () => {
|
|
22
|
+
log(`\n⚠ JAKU: Chromium download interrupted. JAKU is installed — ${MANUAL}`);
|
|
23
|
+
process.exit(0);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function main() {
|
|
27
|
+
const skip =
|
|
28
|
+
process.env.JAKU_SKIP_BROWSER_DOWNLOAD ||
|
|
29
|
+
process.env.PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD;
|
|
30
|
+
|
|
31
|
+
if (skip) {
|
|
32
|
+
log(`JAKU: Skipping Chromium download (skip flag set). ${MANUAL}`);
|
|
33
|
+
return 0;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
log('JAKU: Installing Chromium for Playwright (~170 MB, one-time).');
|
|
37
|
+
log(' Set JAKU_SKIP_BROWSER_DOWNLOAD=1 to skip; JAKU also auto-installs it on first scan.');
|
|
38
|
+
|
|
39
|
+
let res;
|
|
40
|
+
try {
|
|
41
|
+
res = spawnSync('npx', ['playwright', 'install', 'chromium'], {
|
|
42
|
+
stdio: 'inherit',
|
|
43
|
+
shell: process.platform === 'win32',
|
|
44
|
+
});
|
|
45
|
+
} catch (e) {
|
|
46
|
+
log(`⚠ JAKU: Could not auto-install Chromium (${e.message}). ${MANUAL}`);
|
|
47
|
+
return 0;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (res.signal) {
|
|
51
|
+
log(`\n⚠ JAKU: Chromium install was interrupted (${res.signal}). JAKU is installed — ${MANUAL}`);
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
if (res.error) {
|
|
55
|
+
log(`⚠ JAKU: Could not auto-install Chromium (${res.error.message}). ${MANUAL}`);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
if (res.status !== 0) {
|
|
59
|
+
log(`⚠ JAKU: Could not auto-install Chromium. ${MANUAL}`);
|
|
60
|
+
return 0;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
log('JAKU: Chromium ready. ✔');
|
|
64
|
+
return 0;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Always exit 0 — installing the CLI must never fail because of the browser.
|
|
68
|
+
try {
|
|
69
|
+
process.exit(main());
|
|
70
|
+
} catch (e) {
|
|
71
|
+
log(`⚠ JAKU: postinstall encountered an issue (${e.message}). ${MANUAL}`);
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
package/src/agents/ai-agent.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { BaseAgent } from './base-agent.js';
|
|
2
|
+
import { allows, getSafetyMode } from '../utils/safety.js';
|
|
3
|
+
import { generateInjectionPayloads } from '../core/llm/augmentations.js';
|
|
2
4
|
import { AIEndpointDetector } from '../core/ai/ai-endpoint-detector.js';
|
|
3
5
|
import { PromptInjector } from '../core/ai/prompt-injector.js';
|
|
4
6
|
import { JailbreakTester } from '../core/ai/jailbreak-tester.js';
|
|
@@ -34,6 +36,14 @@ export class AIAgent extends BaseAgent {
|
|
|
34
36
|
throw new Error('No surface inventory available — JAKU-CRAWL must run first');
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
// AI endpoint detection and abuse testing send live requests (benign
|
|
40
|
+
// probes + injection payloads), so they require at least safe-active.
|
|
41
|
+
if (!allows(config, 'safe-active')) {
|
|
42
|
+
this._log(`AI abuse testing skipped — requires active probing (current: ${getSafetyMode(config)} mode)`);
|
|
43
|
+
this.progress('complete', 'AI testing skipped (passive mode)', 100);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
// Phase 1: Detect AI endpoints
|
|
38
48
|
this.progress('detect', 'Detecting AI-powered endpoints...', 0);
|
|
39
49
|
|
|
@@ -78,9 +88,10 @@ export class AIAgent extends BaseAgent {
|
|
|
78
88
|
|
|
79
89
|
// Phase 4: System Prompt Extraction
|
|
80
90
|
this.progress('extraction', 'Attempting system prompt extraction...', 50);
|
|
91
|
+
let extractionFindings = [];
|
|
81
92
|
try {
|
|
82
93
|
const extractor = new SystemPromptExtractor(logger);
|
|
83
|
-
|
|
94
|
+
extractionFindings = await extractor.extract(aiSurfaces, sendMessage);
|
|
84
95
|
this.addFindings(extractionFindings);
|
|
85
96
|
this._log(`System prompt extraction: ${extractionFindings.length} leaks`);
|
|
86
97
|
} catch (err) {
|
|
@@ -88,6 +99,41 @@ export class AIAgent extends BaseAgent {
|
|
|
88
99
|
}
|
|
89
100
|
this.progress('extraction', 'System prompt extraction complete', 70);
|
|
90
101
|
|
|
102
|
+
// Phase 4.5: LLM-generated, context-aware injection payloads (optional).
|
|
103
|
+
// Only runs when LLM augmentation is active (egress is auto-disabled in
|
|
104
|
+
// passive mode). Generated DESTRUCTIVE payloads require --aggressive;
|
|
105
|
+
// non-destructive generated probes need safe-active (already satisfied).
|
|
106
|
+
const llmClient = context.llmClient;
|
|
107
|
+
if (llmClient?.isEnabled?.()) {
|
|
108
|
+
try {
|
|
109
|
+
// Reuse the (already-leaked) system prompt as generation context.
|
|
110
|
+
const leaked = extractionFindings
|
|
111
|
+
.map(f => {
|
|
112
|
+
const m = /Extracted content:\n([\s\S]*)/.exec(f.evidence || '');
|
|
113
|
+
return m ? m[1].trim() : '';
|
|
114
|
+
})
|
|
115
|
+
.filter(Boolean)[0] || '';
|
|
116
|
+
|
|
117
|
+
if (leaked) {
|
|
118
|
+
const allowDestructive = allows(config, 'aggressive');
|
|
119
|
+
const generated = await generateInjectionPayloads(llmClient, {
|
|
120
|
+
systemPrompt: leaked,
|
|
121
|
+
surfaceUrl: aiSurfaces[0]?.url || config.target_url,
|
|
122
|
+
allowDestructive,
|
|
123
|
+
});
|
|
124
|
+
if (generated?.length) {
|
|
125
|
+
const genFindings = await injector.injectGenerated(aiSurfaces, generated, { allowDestructive });
|
|
126
|
+
this.addFindings(genFindings);
|
|
127
|
+
this._log(`LLM-generated payloads: ${genFindings.length} findings from ${generated.length} tailored payloads`);
|
|
128
|
+
}
|
|
129
|
+
} else {
|
|
130
|
+
this._log('No leaked system prompt — skipping LLM payload generation');
|
|
131
|
+
}
|
|
132
|
+
} catch (err) {
|
|
133
|
+
this._log(`LLM payload generation failed: ${err.message}`, 'error');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
91
137
|
// Phase 5: Output Analysis (AI-mediated XSS)
|
|
92
138
|
this.progress('output', 'Analyzing AI output sanitization...', 70);
|
|
93
139
|
try {
|
package/src/agents/api-agent.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseAgent } from './base-agent.js';
|
|
2
|
+
import { allows, getSafetyMode } from '../utils/safety.js';
|
|
2
3
|
import { AuthFlowTester } from '../core/api/auth-flow-tester.js';
|
|
3
4
|
import { OAuthProber } from '../core/api/oauth-prober.js';
|
|
4
5
|
import { APIKeyAuditor } from '../core/api/api-key-auditor.js';
|
|
@@ -28,6 +29,14 @@ export class APIAgent extends BaseAgent {
|
|
|
28
29
|
throw new Error('No surface inventory available — JAKU-CRAWL must run first');
|
|
29
30
|
}
|
|
30
31
|
|
|
32
|
+
// API/auth flow verification sends live requests, so it requires at
|
|
33
|
+
// least safe-active. In passive mode it is skipped.
|
|
34
|
+
if (!allows(config, 'safe-active')) {
|
|
35
|
+
this._log(`API & auth flow verification skipped — requires active probing (current: ${getSafetyMode(config)} mode)`);
|
|
36
|
+
this.progress('complete', 'API testing skipped (passive mode)', 100);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
31
40
|
// Phase 1: Auth flow testing
|
|
32
41
|
this.progress('auth', 'Testing authentication flows...', 0);
|
|
33
42
|
try {
|