Skip to content

feat(inquisitor): bridge KCode to Inquisitor for CVE-grade evidence#112

Merged
GaltRanch merged 1 commit into
masterfrom
feat/inquisitor-bridge
May 26, 2026
Merged

feat(inquisitor): bridge KCode to Inquisitor for CVE-grade evidence#112
GaltRanch merged 1 commit into
masterfrom
feat/inquisitor-bridge

Conversation

@GaltRanch

Copy link
Copy Markdown
Contributor

Summary

Bridges KCode (open source, Apache 2.0) to Inquisitor (our paid SaaS, hosted at api.astrolexis.space) for the last-mile of the audit → disclosure pipeline.

KCode keeps doing what it does today, fully open and free: discovery, LLM verification, agentic re-verification, and agentic fix generation. What moves behind the Inquisitor service boundary is the CVE-grade evidence layer — the steps that maintainer security teams need to accept and act on a finding:

  • standalone compilable reproducers
  • adversarial-input binary scans that validate findings against real binaries
  • signed disclosure bundles
  • intake submission (GHSA / Bugcrowd / SOC email / OSS PR)

Why now

We just ran a multi-repo audit campaign against nasa/CryptoLib, nasa/cFS, and nasa/trick. Six PRs landed; one private GHSA filed cleanly; one Bugcrowd submission got bounced with "Not reproducible" — the bounce point was precisely the missing reproducer + binary validation. That's the gap this PR closes, with Inquisitor doing the work and KCode being the friendly local-shell client.

What's in the change

Path Why
src/integrations/inquisitor.ts (new) Bridge client. Reads token from ~/.inquisitor/token (or INQUISITOR_TOKEN env), POSTs to INQUISITOR_URL (default https://api.astrolexis.space/inquisitor/v1), translates HTTP responses into typed InquisitorErrors with actionable hints.
src/cli/commands/reproduce.ts (new) kcode reproduce <finding-id> — pulls a confirmed finding from AUDIT_REPORT.json, sends it to Inquisitor's Mender sidecar, writes the returned reproducer artifacts to ./repro/.
src/cli/commands/validate.ts (new) kcode validate <binary> — submits a compiled target to Inquisitor's VulnHunter agent for adversarial-input scanning, prints crash summary.
src/cli/commands/bundle.ts (new) kcode bundle <finding-ids…> — generates a signed disclosure bundle (GHSA / Bugcrowd / SOC email / OSS PR formats) from a set of confirmed findings + optional reproducer dir + screencast.
src/cli/commands/disclose.ts (new) kcode disclose <bundle.tar.gz> --intake <target> — submits the bundle to the chosen intake. Supports --dry-run for validation without submission.
src/cli/commands/index.ts Re-export the four new commands.
src/index.ts Import + register the four new commands.
README.md New section "From candidates to CVE-grade evidence" documenting the bridge, the env vars, and the pricing pointer.

UX when Inquisitor is not available

Existing KCode users see nothing change. Only people who explicitly invoke one of the four new commands hit the gate, and the gate is friendly:

✗ Inquisitor token not found.

  These commands require an Inquisitor account (KCode's paid sister service
  for CVE-grade evidence: standalone reproducers, binary validation, signed
  disclosure bundles).

    • Sign up: https://astrolexis.space/inquisitor
    • Already have a token? Save it with:
        mkdir -p ~/.inquisitor && echo '<your-token>' > ~/.inquisitor/token
      or export INQUISITOR_TOKEN=<your-token> in your shell.

Other failure modes covered (with hints):

  • Bridge unreachable (network / DNS / Astrolexis down)
  • Token rejected (401)
  • No sessions remaining (402, points at billing URL)
  • Tier doesn't include the action (403, free tier disables external disclose)
  • Server error (any other non-2xx)

Configuration

Env var Default
INQUISITOR_URL https://api.astrolexis.space/inquisitor/v1
INQUISITOR_TOKEN_FILE ~/.inquisitor/token
INQUISITOR_TOKEN overrides the token file when set

Self-hosted Enterprise tier just points INQUISITOR_URL at their own daemon. KCode is endpoint-agnostic.

Test plan

  • bun run typecheck — clean (no new errors).
  • bun run lint — clean after lint:fix.
  • kcode --help — four new commands appear in the subcommand list.
  • kcode validate /bin/ls with no token + unreachable URL — prints the upsell message and exits 1.
  • End-to-end smoke against a live Inquisitor endpoint — pending the Inquisitor-side endpoints landing.

Rollout

Backwards-compatible. Existing kcode audit, kcode --print, and every other command behave identically. The four new commands appear in --help but only do anything for users who set up Inquisitor.

When Inquisitor's astrolexis-api exposes the matching /v1/inquisitor/{preflight,reproduce,validate,bundle,disclose} endpoints publicly, these commands light up immediately for anyone with a token. No KCode release required.

— Bruno Aiub · AstroLexis · Kulvex Code

KCode owns the open-source discovery → verify → fix pipeline. The
final-mile work — standalone reproducer synthesis, adversarial binary
scan, signed disclosure bundle, intake submission — moves to Inquisitor,
our paid sister service. KCode talks to it over HTTP through this
bridge.

New module:
  src/integrations/inquisitor.ts  bridge client + preflight + errors

New commands (all require Inquisitor account):
  kcode reproduce <id>     standalone compilable reproducer (Mender)
  kcode validate <bin>     adversarial-input binary scan (VulnHunter)
  kcode bundle <ids…>      signed disclosure bundle
  kcode disclose <path>    submit bundle to intake (GHSA/Bugcrowd/email/PR)

Configuration via env:
  INQUISITOR_URL          default https://api.astrolexis.space/inquisitor/v1
  INQUISITOR_TOKEN_FILE   default ~/.inquisitor/token
  INQUISITOR_TOKEN        env override of the token file

UX when no token / unreachable: clear upsell message with signup link.
Existing kcode commands (audit, --print, agentic fix) remain fully open
and free; only the new commands are gated.

Signed-off-by: GaltRanch <bruno@nexocore.uy>
@github-actions

Copy link
Copy Markdown

🔍 KCode Security Audit

Audit Report — KCode

Auditor: Astrolexis.space — Kulvex Code
Date: 2026-05-26
Project: /home/runner/work/KCode/KCode
Languages: typescript


Audit Confidence

Score: 25 / 100

Subscore Value Weight
Coverage 38 25%
Verifier n/a 20%
AST 100 15%
Noise (FP justification) n/a 20%
Fixability (rewrite-class) n/a 20%

Coverage: 500 / 1305 files (38%) — full scan
Verifier: skipped (static-only output — see warnings)
AST grammars: 1 loaded
Findings: 278 confirmed · 0 false-positive · 0 needs-context
Autofix: 0 rewrite · 264 annotate · 14 manual-only
Pack breakdown: 235 general · 43 web

⚠ Warnings:

  • Verifier was skipped — every candidate is reported without LLM filtering. The 'confirmed' bucket contains raw regex hits; treat counts as upper-bound noise.
  • Coverage truncated — only 500 / 1305 files scanned. Re-run with --max-files 1305 for full coverage.
  • Audit-disabled: 34 file(s) carried a kcode-disable: audit directive and were skipped from pattern matching. Files: ai-ml.ts, cloud.ts, cpp.ts, +31 more.

Coverage

  • Files in project: 1305
  • Files scanned: 500 (38%)
  • Truncated: yes (805 files skipped by --max-files)
  • Max-files cap: 500 (user)

⚠ This report covers only 500/1305 source files. Findings below reflect the scanned subset, not the whole codebase. Re-run with --max-files 1305 (or higher) for full coverage.

Summary

  • Files scanned: 500
  • Candidates found: 278
  • Confirmed findings: 278
  • False positives: 0
  • Scan duration: 42.3s

Severity breakdown

Severity Count
🔴 CRITICAL 145
🟠 HIGH 123
🟡 MEDIUM 5
🟢 LOW 5

Full report

Audit Report — KCode

Auditor: Astrolexis.space — Kulvex Code
Date: 2026-05-26
Project: /home/runner/work/KCode/KCode
Languages: typescript


Audit Confidence

Score: 25 / 100

Subscore Value Weight
Coverage 38 25%
Verifier n/a 20%
AST 100 15%
Noise (FP justification) n/a 20%
Fixability (rewrite-class) n/a 20%

Coverage: 500 / 1305 files (38%) — full scan
Verifier: skipped (static-only output — see warnings)
AST grammars: 1 loaded
Findings: 278 confirmed · 0 false-positive · 0 needs-context
Autofix: 0 rewrite · 264 annotate · 14 manual-only
Pack breakdown: 235 general · 43 web

⚠ Warnings:

  • Verifier was skipped — every candidate is reported without LLM filtering. The 'confirmed' bucket contains raw regex hits; treat counts as upper-bound noise.
  • Coverage truncated — only 500 / 1305 files scanned. Re-run with --max-files 1305 for full coverage.
  • Audit-disabled: 34 file(s) carried a kcode-disable: audit directive and were skipped from pattern matching. Files: ai-ml.ts, cloud.ts, cpp.ts, +31 more.

Coverage

  • Files in project: 1305
  • Files scanned: 500 (38%)
  • Truncated: yes (805 files skipped by --max-files)
  • Max-files cap: 500 (user)

⚠ This report covers only 500/1305 source files. Findings below reflect the scanned subset, not the whole codebase. Re-run with --max-files 1305 (or higher) for full coverage.

Summary

  • Files scanned: 500
  • Candidates found: 278
  • Confirmed findings: 278
  • False positives: 0
  • Scan duration: 42.3s

Severity breakdown

Severity Count
🔴 CRITICAL 145
🟠 HIGH 123
🟡 MEDIUM 5
🟢 LOW 5

Findings

1. 🔴 Shell command with template literal (injection) — CWE-78

File: backend/src/db.ts:23
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

21: 
22: function migrate(db: Database): void {
23:   db.exec(`
24:     CREATE TABLE IF NOT EXISTS customers (
25:       id            TEXT PRIMARY KEY,
26:       stripe_id     TEXT UNIQUE NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


2. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: backend/src/index.ts:353
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


3. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/cli/commands/dashboard.ts:34
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setInterval(display)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


4. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/cli/commands/update.ts:93
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setTimeout(() => {
              process.stdin.pause();
              resolve("y");
    …)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


5. 🔴 Shell command with template literal (injection) — CWE-78

File: src/cli/commands/web.ts:56
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

54:                   ? "start"
55:                   : "xdg-open";
56:             exec(`${cmd} "${fullUrl}"`);
57:           } catch {
58:             console.log(`  Open in browser: ${fullUrl}`);
59:           }

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


6. 🔴 Command built from string concatenation with variable — CWE-77

File: src/cli/commands/web.ts:56
Severity: CRITICAL
Pattern: uni-007-command-injection-concat

Why this matters:
Building shell commands via string concatenation or interpolation with user-controlled variables allows command injection. The attacker can break out of the intended command and execute arbitrary commands.

Code:

54:                   ? "start"
55:                   : "xdg-open";
56:             exec(`${cmd} "${fullUrl}"`);
57:           } catch {
58:             console.log(`  Open in browser: ${fullUrl}`);
59:           }

Verification: Verification skipped — static-only mode

Fix template: Use parameterized execution: subprocess.run([cmd, arg1, arg2]) instead of shell string. Never pass user input through a shell.


7. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/core/agents/executor.ts:291
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setTimeout(() => {
        if (finished) return;
        log.warn("agent-executor", `${a…)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


8. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/audit-engine/audit-history.ts:39
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

37:     }
38:     const db = new Database(path);
39:     db.exec(`
40:       CREATE TABLE IF NOT EXISTS verdicts (
41:         id INTEGER PRIMARY KEY AUTOINCREMENT,
42:         pattern_id TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


9. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/audit-engine/llm-callback.ts:138
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


10. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/audit-engine/pr-generator.ts:1050
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


11. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-engine/scanner.ts:772
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


12. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-engine/taint/java.ts:760
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(fileContent)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


13. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/audit-engine/verifier.ts:1024
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


14. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:128
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


15. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:143
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


16. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:151
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


17. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:155
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


18. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:162
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


19. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:166
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


20. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:312
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


21. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/audit-guards.ts:334
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


22. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/audit-logger.ts:52
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

50: 
51:     // Create audit table
52:     db.exec(`CREATE TABLE IF NOT EXISTS audit_log (
53:       id INTEGER PRIMARY KEY AUTOINCREMENT,
54:       timestamp TEXT NOT NULL DEFAULT (datetime('now')),
55:       event_type TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


23. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/audit-logger.ts:70
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

68: 
69:     // Index for common queries
70:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_log(timestamp)`);
71:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_event_type ON audit_log(event_type)`);
72:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_session ON audit_log(session_id)`);
73: 

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


24. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/audit-logger.ts:71
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

69:     // Index for common queries
70:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_log(timestamp)`);
71:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_event_type ON audit_log(event_type)`);
72:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_session ON audit_log(session_id)`);
73: 
74:     _insertStmt = db.prepare(`INSERT INTO audit_log

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


25. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/audit-logger.ts:72
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

70:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_log(timestamp)`);
71:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_event_type ON audit_log(event_type)`);
72:     db.exec(`CREATE INDEX IF NOT EXISTS idx_audit_session ON audit_log(session_id)`);
73: 
74:     _insertStmt = db.prepare(`INSERT INTO audit_log
75:       (event_type, tool_name, action, status, reason, model, session_id, org_id, input_summary, cost_usd, token_count, duration_ms)

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


26. 🔴 child_process.exec / spawn / execFile of a tainted expression (taint-lite) — CWE-78

File: src/core/auth/oauth-flow.ts:211
Severity: CRITICAL
Pattern: js-ast-006-exec-of-tainted-expression

Why this matters:
child_process.exec / spawn / execFile with a command string the taint walker traces back to an external source. js-ast-002 catches the bare-parameter case; this catches concat ('ls ' + userPath) and assignment-propagated taint patterns that regex misses.

Code:

.spawn(cmd)  // command string is tainted from req/request/process/ctx/document/location (possibly via assignment + concat)

Verification: Verification skipped — static-only mode

Fix template: Use execFile/spawn with the args array form and a hardcoded command, then shell-escape every tainted argv entry. Never build the shell command via string concat with external input.


27. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/core/auth/oauth-flow.ts:222
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setTimeout(() => {
        server.stop();
        reject(new Error("OAuth callback timed…)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


28. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/core/auth/oauth-flow.ts:421
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setTimeout(() => {
        rl.close();
        reject(new Error("Timed out waiting for a…)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


29. 🔴 eval / exec / Function / new Function with user input — CWE-95

File: src/core/auto-agents.ts:175
Severity: CRITICAL
Pattern: des-003-eval-user-input

Why this matters:
eval/exec on user input is full RCE. setTimeout/setInterval/Function/new Function with a string argument is an alias for eval. Even compile(user_str) loads attacker code into Python's interpreter state.

Code:

173:         this.notifyProgress();
174: 
175:         execFile(
176:           kcodeBin,
177:           args,
178:           {

Verification: Verification skipped — static-only mode

Fix template: Use ast.literal_eval (Python) or JSON.parse (JS) for data literals. Build a domain-specific parser for anything else.


30. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/auto-update.ts:504
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

502:   try {
503:     // bspatch <oldfile> <newfile> <patchfile>
504:     execSync(
505:       `bspatch ${JSON.stringify(currentBinary)} ${JSON.stringify(outPath)} ${JSON.stringify(patchPath)}`,
506:       { stdio: "pipe", timeout: 120_000 },
507:     );

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


31. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/bash-spawn-verifier.ts:408
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


32. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/benchmark-driver.ts:21
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


33. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/benchmarks.ts:12
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

10: export function initBenchmarkSchema(): void {
11:   const db = getDb();
12:   db.exec(`
13:     CREATE TABLE IF NOT EXISTS benchmarks (
14:       id INTEGER PRIMARY KEY AUTOINCREMENT,
15:       model TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


34. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/benchmarks.ts:24
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

22:     )
23:   `);
24:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_model ON benchmarks(model)`);
25:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_date ON benchmarks(created_at)`);
26: }
27: 

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


35. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/benchmarks.ts:25
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

23:   `);
24:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_model ON benchmarks(model)`);
25:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_date ON benchmarks(created_at)`);
26: }
27: 
28: // ─── Types ──────────────────────────────────────────────────────

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


36. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/change-review.ts:460
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

458:   let numstatOutput: string;
459:   try {
460:     nameStatusOutput = execSync(`git diff ${diffFlag} --name-status`, {
461:       cwd,
462:       encoding: "utf-8",
463:       timeout: 10000,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


37. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/change-review.ts:465
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

463:       timeout: 10000,
464:     });
465:     numstatOutput = execSync(`git diff ${diffFlag} --numstat`, {
466:       cwd,
467:       encoding: "utf-8",
468:       timeout: 10000,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


38. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/claim-reality-check.ts:105
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(assistantText)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


39. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/claim-reality-check.ts:394
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(text)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


40. 🔴 child_process.exec / spawn / execFile of a tainted expression (taint-lite) — CWE-78

File: src/core/clipboard.ts:43
Severity: CRITICAL
Pattern: js-ast-006-exec-of-tainted-expression

Why this matters:
child_process.exec / spawn / execFile with a command string the taint walker traces back to an external source. js-ast-002 catches the bare-parameter case; this catches concat ('ls ' + userPath) and assignment-propagated taint patterns that regex misses.

Code:

.spawn([command, ...args])  // command string is tainted from req/request/process/ctx/document/location (possibly via assignment + concat)

Verification: Verification skipped — static-only mode

Fix template: Use execFile/spawn with the args array form and a hardcoded command, then shell-escape every tainted argv entry. Never build the shell command via string concat with external input.


41. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/codebase-index.ts:217
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


42. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/codebase-index.ts:223
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


43. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/codebase-index.ts:233
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


44. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/codebase-index.ts:239
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


45. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/codebase-index.ts:253
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


46. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/codebase-index.ts:259
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


47. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/codebase-index.ts:272
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

270:     const db = getDb();
271:     try {
272:       db.exec(`CREATE TABLE IF NOT EXISTS codebase_index (
273:         path TEXT PRIMARY KEY,
274:         relative_path TEXT NOT NULL,
275:         ext TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


48. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/codebase-index.ts:286
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

284:       // Add definitions column if missing (migration for existing DBs)
285:       try {
286:         db.exec(`ALTER TABLE codebase_index ADD COLUMN definitions TEXT DEFAULT '[]'`);
287:       } catch {
288:         /* column already exists */
289:       }

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


49. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-retry.ts:67
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


50. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/conversation-streaming.ts:212
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(text)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


51. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-task-routing.ts:175
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


52. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-task-routing.ts:186
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


53. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-task-routing.ts:464
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


54. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-task-routing.ts:468
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


55. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-task-routing.ts:492
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


56. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/conversation-task-routing.ts:505
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


57. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/core/coordinator/coordinator.ts:134
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setTimeout(() => {
        if (handle.status === "running") {
          handle.status = …)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


58. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/dangerous-patterns.ts:419
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(command)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


59. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/dashboard/analyzer.ts:31
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.spawn(cmd)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


60. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/dashboard/metrics.ts:10
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.spawn(cmd)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


61. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:69
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

67: function initSchema(db: Database): void {
68:   // narrative.ts tables
69:   db.exec(`CREATE TABLE IF NOT EXISTS narrative (
70:     id INTEGER PRIMARY KEY AUTOINCREMENT,
71:     summary TEXT NOT NULL,
72:     project TEXT NOT NULL DEFAULT '',

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


62. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:79
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

77: 
78:   // user-model.ts tables
79:   db.exec(`CREATE TABLE IF NOT EXISTS user_model (
80:     key TEXT PRIMARY KEY, value REAL NOT NULL, samples INTEGER NOT NULL DEFAULT 1,
81:     updated_at TEXT NOT NULL DEFAULT (datetime('now'))
82:   )`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


63. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:83
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

81:     updated_at TEXT NOT NULL DEFAULT (datetime('now'))
82:   )`);
83:   db.exec(`CREATE TABLE IF NOT EXISTS user_interests (
84:     topic TEXT PRIMARY KEY, frequency INTEGER NOT NULL DEFAULT 1,
85:     updated_at TEXT NOT NULL DEFAULT (datetime('now'))
86:   )`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


64. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:87
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

85:     updated_at TEXT NOT NULL DEFAULT (datetime('now'))
86:   )`);
87:   db.exec(`CREATE TABLE IF NOT EXISTS user_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`);
88: 
89:   // world-model.ts tables
90:   db.exec(`CREATE TABLE IF NOT EXISTS predictions (

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


65. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:90
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

88: 
89:   // world-model.ts tables
90:   db.exec(`CREATE TABLE IF NOT EXISTS predictions (
91:     id INTEGER PRIMARY KEY AUTOINCREMENT,
92:     action TEXT NOT NULL,
93:     expected TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


66. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:102
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

100:   // learn.ts tables
101:   db.exec("PRAGMA foreign_keys=ON");
102:   db.exec(`CREATE TABLE IF NOT EXISTS learnings (
103:     id INTEGER PRIMARY KEY AUTOINCREMENT,
104:     topic TEXT NOT NULL,
105:     content TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


67. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:113
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

111:     access_count INTEGER DEFAULT 0
112:   )`);
113:   db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS learnings_fts USING fts5(
114:     topic, content, tags, content='learnings', content_rowid='id'
115:   )`);
116:   db.exec(`CREATE TRIGGER IF NOT EXISTS learnings_ai AFTER INSERT ON learnings BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


68. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:116
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

114:     topic, content, tags, content='learnings', content_rowid='id'
115:   )`);
116:   db.exec(`CREATE TRIGGER IF NOT EXISTS learnings_ai AFTER INSERT ON learnings BEGIN
117:     INSERT INTO learnings_fts(rowid, topic, content, tags) VALUES (new.id, new.topic, new.content, new.tags);
118:   END`);
119:   db.exec(`CREATE TRIGGER IF NOT EXISTS learnings_ad AFTER DELETE ON learnings BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


69. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:119
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

117:     INSERT INTO learnings_fts(rowid, topic, content, tags) VALUES (new.id, new.topic, new.content, new.tags);
118:   END`);
119:   db.exec(`CREATE TRIGGER IF NOT EXISTS learnings_ad AFTER DELETE ON learnings BEGIN
120:     INSERT INTO learnings_fts(learnings_fts, rowid, topic, content, tags) VALUES ('delete', old.id, old.topic, old.content, old.tags);
121:   END`);
122:   db.exec(`CREATE TRIGGER IF NOT EXISTS learnings_au AFTER UPDATE ON learnings BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


70. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:122
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

120:     INSERT INTO learnings_fts(learnings_fts, rowid, topic, content, tags) VALUES ('delete', old.id, old.topic, old.content, old.tags);
121:   END`);
122:   db.exec(`CREATE TRIGGER IF NOT EXISTS learnings_au AFTER UPDATE ON learnings BEGIN
123:     INSERT INTO learnings_fts(learnings_fts, rowid, topic, content, tags) VALUES ('delete', old.id, old.topic, old.content, old.tags);
124:     INSERT INTO learnings_fts(rowid, topic, content, tags) VALUES (new.id, new.topic, new.content, new.tags);
125:   END`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


71. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:128
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

126: 
127:   // distillation.ts tables — knowledge distillation (RAG-based few-shot learning)
128:   db.exec(`CREATE TABLE IF NOT EXISTS distilled_examples (
129:     id INTEGER PRIMARY KEY AUTOINCREMENT,
130:     user_query TEXT NOT NULL,
131:     assistant_response TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


72. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:141
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

139:     created_at TEXT NOT NULL DEFAULT (datetime('now'))
140:   )`);
141:   db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS distilled_fts USING fts5(
142:     user_query, assistant_response, tags, content='distilled_examples', content_rowid='id'
143:   )`);
144:   db.exec(`CREATE TRIGGER IF NOT EXISTS distilled_ai AFTER INSERT ON distilled_examples BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


73. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:144
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

142:     user_query, assistant_response, tags, content='distilled_examples', content_rowid='id'
143:   )`);
144:   db.exec(`CREATE TRIGGER IF NOT EXISTS distilled_ai AFTER INSERT ON distilled_examples BEGIN
145:     INSERT INTO distilled_fts(rowid, user_query, assistant_response, tags)
146:     VALUES (new.id, new.user_query, new.assistant_response, new.tags);
147:   END`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


74. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:148
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

146:     VALUES (new.id, new.user_query, new.assistant_response, new.tags);
147:   END`);
148:   db.exec(`CREATE TRIGGER IF NOT EXISTS distilled_ad AFTER DELETE ON distilled_examples BEGIN
149:     INSERT INTO distilled_fts(distilled_fts, rowid, user_query, assistant_response, tags)
150:     VALUES ('delete', old.id, old.user_query, old.assistant_response, old.tags);
151:   END`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


75. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:152
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

150:     VALUES ('delete', old.id, old.user_query, old.assistant_response, old.tags);
151:   END`);
152:   db.exec(`CREATE TRIGGER IF NOT EXISTS distilled_au AFTER UPDATE ON distilled_examples BEGIN
153:     INSERT INTO distilled_fts(distilled_fts, rowid, user_query, assistant_response, tags)
154:     VALUES ('delete', old.id, old.user_query, old.assistant_response, old.tags);
155:     INSERT INTO distilled_fts(rowid, user_query, assistant_response, tags)

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


76. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:160
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

158: 
159:   // benchmarks.ts tables — model quality tracking
160:   db.exec(`CREATE TABLE IF NOT EXISTS benchmarks (
161:     id INTEGER PRIMARY KEY AUTOINCREMENT,
162:     model TEXT NOT NULL,
163:     task_type TEXT NOT NULL DEFAULT 'general',

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


77. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:170
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

168:     created_at TEXT NOT NULL DEFAULT (datetime('now'))
169:   )`);
170:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_model ON benchmarks(model)`);
171:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_date ON benchmarks(created_at)`);
172: 
173:   // plan.ts tables — structured plan persistence

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


78. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:171
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

169:   )`);
170:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_model ON benchmarks(model)`);
171:   db.exec(`CREATE INDEX IF NOT EXISTS idx_bench_date ON benchmarks(created_at)`);
172: 
173:   // plan.ts tables — structured plan persistence
174:   db.exec(`CREATE TABLE IF NOT EXISTS plans (

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


79. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:174
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

172: 
173:   // plan.ts tables — structured plan persistence
174:   db.exec(`CREATE TABLE IF NOT EXISTS plans (
175:     id TEXT PRIMARY KEY,
176:     title TEXT NOT NULL,
177:     steps TEXT NOT NULL DEFAULT '[]',

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


80. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:183
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

181: 
182:   // analytics.ts tables — persistent tool usage analytics
183:   db.exec(`CREATE TABLE IF NOT EXISTS tool_analytics (
184:     id INTEGER PRIMARY KEY AUTOINCREMENT,
185:     session_id TEXT NOT NULL DEFAULT '',
186:     tool_name TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


81. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:195
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

193:     created_at TEXT NOT NULL DEFAULT (datetime('now'))
194:   )`);
195:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_tool ON tool_analytics(tool_name)`);
196:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_date ON tool_analytics(created_at)`);
197:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_session ON tool_analytics(session_id)`);
198: 

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


82. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:196
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

194:   )`);
195:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_tool ON tool_analytics(tool_name)`);
196:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_date ON tool_analytics(created_at)`);
197:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_session ON tool_analytics(session_id)`);
198: 
199:   // tasks.ts tables — persistent task management

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


83. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:197
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

195:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_tool ON tool_analytics(tool_name)`);
196:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_date ON tool_analytics(created_at)`);
197:   db.exec(`CREATE INDEX IF NOT EXISTS idx_analytics_session ON tool_analytics(session_id)`);
198: 
199:   // tasks.ts tables — persistent task management
200:   db.exec(`CREATE TABLE IF NOT EXISTS tasks (

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


84. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:200
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

198: 
199:   // tasks.ts tables — persistent task management
200:   db.exec(`CREATE TABLE IF NOT EXISTS tasks (
201:     id TEXT PRIMARY KEY,
202:     title TEXT NOT NULL,
203:     description TEXT DEFAULT '',

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


85. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:213
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

211:     completed_at TEXT DEFAULT NULL
212:   )`);
213:   db.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)`);
214:   db.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id)`);
215: 
216:   // transcript-search.ts tables — FTS5 over transcripts for instant search

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


86. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:214
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

212:   )`);
213:   db.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)`);
214:   db.exec(`CREATE INDEX IF NOT EXISTS idx_tasks_session ON tasks(session_id)`);
215: 
216:   // transcript-search.ts tables — FTS5 over transcripts for instant search
217:   db.exec(`CREATE TABLE IF NOT EXISTS transcript_entries (

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


87. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:217
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

215: 
216:   // transcript-search.ts tables — FTS5 over transcripts for instant search
217:   db.exec(`CREATE TABLE IF NOT EXISTS transcript_entries (
218:     id INTEGER PRIMARY KEY AUTOINCREMENT,
219:     session_file TEXT NOT NULL,
220:     role TEXT NOT NULL DEFAULT '',

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


88. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:225
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

223:     timestamp TEXT NOT NULL DEFAULT (datetime('now'))
224:   )`);
225:   db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS transcript_fts USING fts5(
226:     content, session_file, role, content='transcript_entries', content_rowid='id'
227:   )`);
228:   db.exec(`CREATE TRIGGER IF NOT EXISTS transcript_ai AFTER INSERT ON transcript_entries BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


89. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:228
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

226:     content, session_file, role, content='transcript_entries', content_rowid='id'
227:   )`);
228:   db.exec(`CREATE TRIGGER IF NOT EXISTS transcript_ai AFTER INSERT ON transcript_entries BEGIN
229:     INSERT INTO transcript_fts(rowid, content, session_file, role) VALUES (new.id, new.content, new.session_file, new.role);
230:   END`);
231:   db.exec(`CREATE TRIGGER IF NOT EXISTS transcript_ad AFTER DELETE ON transcript_entries BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


90. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:231
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

229:     INSERT INTO transcript_fts(rowid, content, session_file, role) VALUES (new.id, new.content, new.session_file, new.role);
230:   END`);
231:   db.exec(`CREATE TRIGGER IF NOT EXISTS transcript_ad AFTER DELETE ON transcript_entries BEGIN
232:     INSERT INTO transcript_fts(transcript_fts, rowid, content, session_file, role) VALUES ('delete', old.id, old.content, old.session_file, old.role);
233:   END`);
234:   db.exec(`CREATE INDEX IF NOT EXISTS idx_transcript_session ON transcript_entries(session_file)`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


91. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:234
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

232:     INSERT INTO transcript_fts(transcript_fts, rowid, content, session_file, role) VALUES ('delete', old.id, old.content, old.session_file, old.role);
233:   END`);
234:   db.exec(`CREATE INDEX IF NOT EXISTS idx_transcript_session ON transcript_entries(session_file)`);
235: 
236:   // branch-manager.ts tables — persistent conversation branch tracking
237:   db.exec(`CREATE TABLE IF NOT EXISTS conversation_branches (

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


92. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:237
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

235: 
236:   // branch-manager.ts tables — persistent conversation branch tracking
237:   db.exec(`CREATE TABLE IF NOT EXISTS conversation_branches (
238:     id TEXT PRIMARY KEY,
239:     parent_id TEXT,
240:     label TEXT DEFAULT '',

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


93. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:246
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

244:     status TEXT DEFAULT 'active'
245:   )`);
246:   db.exec(`CREATE INDEX IF NOT EXISTS idx_branches_parent ON conversation_branches(parent_id)`);
247:   db.exec(`CREATE INDEX IF NOT EXISTS idx_branches_status ON conversation_branches(status)`);
248: 
249:   // rag/vector-store.ts tables — RAG engine chunk + embedding storage

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


94. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:247
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

245:   )`);
246:   db.exec(`CREATE INDEX IF NOT EXISTS idx_branches_parent ON conversation_branches(parent_id)`);
247:   db.exec(`CREATE INDEX IF NOT EXISTS idx_branches_status ON conversation_branches(status)`);
248: 
249:   // rag/vector-store.ts tables — RAG engine chunk + embedding storage
250:   db.exec(`CREATE TABLE IF NOT EXISTS rag_chunks (

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


95. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/db.ts:250
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

248: 
249:   // rag/vector-store.ts tables — RAG engine chunk + embedding storage
250:   db.exec(`CREATE TABLE IF NOT EXISTS rag_chunks (
251:     id TEXT PRIMARY KEY,
252:     file_path TEXT NOT NULL,
253:     relative_path TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


96. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/debug-engine/evidence-collector.ts:54
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


97. 🔴 SQL query built via string concatenation with variables — CWE-89

File: src/core/distillation.ts:449
Severity: CRITICAL
Pattern: inj-001-sql-string-concat

Why this matters:
Concatenating user input into SQL queries is SQL injection. The canonical attack: login form with username admin' OR 1=1 -- bypasses auth. CVE-2023-32707 and thousands of variants.

Code:

447:     const ids = rows.map((r) => r.id);
448:     const placeholders = ids.map(() => "?").join(",");
449:     db.query(
450:       `UPDATE distilled_examples SET use_count = use_count + 1 WHERE id IN (${placeholders})`,
451:     ).run(...ids);
452: 

Verification: Verification skipped — static-only mode

Fix template: Use parameterized queries: cursor.execute('SELECT * FROM u WHERE id = ?', (user_id,)) — NOT f'... {user_id}'.


98. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/doctor.ts:24
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.spawn(cmd)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


99. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/doctor/checks/gpu-check.ts:8
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.spawn(cmd)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


100. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/dream/dream-tasks.ts:62
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


101. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/dream/dream-tasks.ts:107
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


102. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/dream/dream-tasks.ts:152
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


103. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/dream/dream-tasks.ts:198
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


104. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/github-claim-grounding.ts:55
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(text)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


105. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/gpu-availability.ts:122
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

120:   for (const smiPath of candidatePaths) {
121:     try {
122:       const out = execSync(`${smiPath} ${query}`, {
123:         encoding: "utf-8",
124:         timeout: 5_000,
125:         stdio: ["pipe", "pipe", "pipe"],

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


106. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/hardware.ts:94
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

92:     for (const smiPath of nvidiaSmiPaths) {
93:       try {
94:         output = execSync(`${smiPath} ${queryArgs}`, {
95:           encoding: "utf-8",
96:           timeout: 10000,
97:           stdio: ["pipe", "pipe", "pipe"],

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


107. 🔴 child_process.exec / spawn / execFile of a tainted expression (taint-lite) — CWE-78

File: src/core/hardware/detector.ts:262
Severity: CRITICAL
Pattern: js-ast-006-exec-of-tainted-expression

Why this matters:
child_process.exec / spawn / execFile with a command string the taint walker traces back to an external source. js-ast-002 catches the bare-parameter case; this catches concat ('ls ' + userPath) and assignment-propagated taint patterns that regex misses.

Code:

.spawnSync(["df", "-B1", home])  // command string is tainted from req/request/process/ctx/document/location (possibly via assignment + concat)

Verification: Verification skipped — static-only mode

Fix template: Use execFile/spawn with the args array form and a hardcoded command, then shell-escape every tainted argv entry. Never build the shell command via string concat with external input.


108. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/core/hook-executor.ts:417
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setTimeout(() => {
      try {
        proc.kill();
      } catch (err) {
        log.de…)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


109. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/kodi-model.ts:421
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


110. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/kodi-model.ts:451
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


111. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/llama-server.ts:142
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


112. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/llama-server.ts:209
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


113. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/llama-server.ts:493
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


114. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/llama-server.ts:535
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


115. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/lsp.ts:318
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


116. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/mcp-aliases.ts:22
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

20:   if (schemaInitialized) return;
21:   const db = getDb();
22:   db.exec(`
23:     CREATE TABLE IF NOT EXISTS mcp_tool_aliases (
24:       alias TEXT PRIMARY KEY,
25:       target TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


117. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/mcp-client.ts:754
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


118. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:49
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

47: 
48: export function initMemoryStoreSchema(db: Database): void {
49:   db.exec(`CREATE TABLE IF NOT EXISTS memory_store (
50:     id INTEGER PRIMARY KEY AUTOINCREMENT,
51:     category TEXT NOT NULL DEFAULT 'fact',
52:     key TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


119. 🔴 eval / exec / Function / new Function with user input — CWE-95

File: src/core/memory-store.ts:49
Severity: CRITICAL
Pattern: des-003-eval-user-input

Why this matters:
eval/exec on user input is full RCE. setTimeout/setInterval/Function/new Function with a string argument is an alias for eval. Even compile(user_str) loads attacker code into Python's interpreter state.

Code:

47: 
48: export function initMemoryStoreSchema(db: Database): void {
49:   db.exec(`CREATE TABLE IF NOT EXISTS memory_store (
50:     id INTEGER PRIMARY KEY AUTOINCREMENT,
51:     category TEXT NOT NULL DEFAULT 'fact',
52:     key TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use ast.literal_eval (Python) or JSON.parse (JS) for data literals. Build a domain-specific parser for anything else.


120. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:63
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

61:   )`);
62: 
63:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_project ON memory_store(project)`);
64:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_category ON memory_store(category)`);
65:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_approved ON memory_store(approved)`);
66: 

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


121. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:64
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

62: 
63:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_project ON memory_store(project)`);
64:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_category ON memory_store(category)`);
65:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_approved ON memory_store(approved)`);
66: 
67:   db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_store_fts USING fts5(

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


122. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:65
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

63:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_project ON memory_store(project)`);
64:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_category ON memory_store(category)`);
65:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_approved ON memory_store(approved)`);
66: 
67:   db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_store_fts USING fts5(
68:     key, content, category, content='memory_store', content_rowid='id'

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


123. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:67
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

65:   db.exec(`CREATE INDEX IF NOT EXISTS idx_memory_store_approved ON memory_store(approved)`);
66: 
67:   db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_store_fts USING fts5(
68:     key, content, category, content='memory_store', content_rowid='id'
69:   )`);
70: 

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


124. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:71
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

69:   )`);
70: 
71:   db.exec(`CREATE TRIGGER IF NOT EXISTS memory_store_ai AFTER INSERT ON memory_store BEGIN
72:     INSERT INTO memory_store_fts(rowid, key, content, category) VALUES (new.id, new.key, new.content, new.category);
73:   END`);
74:   db.exec(`CREATE TRIGGER IF NOT EXISTS memory_store_ad AFTER DELETE ON memory_store BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


125. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:74
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

72:     INSERT INTO memory_store_fts(rowid, key, content, category) VALUES (new.id, new.key, new.content, new.category);
73:   END`);
74:   db.exec(`CREATE TRIGGER IF NOT EXISTS memory_store_ad AFTER DELETE ON memory_store BEGIN
75:     INSERT INTO memory_store_fts(memory_store_fts, rowid, key, content, category) VALUES ('delete', old.id, old.key, old.content, old.category);
76:   END`);
77:   db.exec(`CREATE TRIGGER IF NOT EXISTS memory_store_au AFTER UPDATE ON memory_store BEGIN

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


126. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/memory-store.ts:77
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

75:     INSERT INTO memory_store_fts(memory_store_fts, rowid, key, content, category) VALUES ('delete', old.id, old.key, old.content, old.category);
76:   END`);
77:   db.exec(`CREATE TRIGGER IF NOT EXISTS memory_store_au AFTER UPDATE ON memory_store BEGIN
78:     INSERT INTO memory_store_fts(memory_store_fts, rowid, key, content, category) VALUES ('delete', old.id, old.key, old.content, old.category);
79:     INSERT INTO memory_store_fts(rowid, key, content, category) VALUES (new.id, new.key, new.content, new.category);
80:   END`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


127. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/model-engine.ts:368
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

366:   for (const cmd of prerequisites) {
367:     try {
368:       execSync(`which ${cmd}`, { stdio: "pipe", timeout: 5000 });
369:     } catch {
370:       log.error("setup", `Build prerequisite missing: ${cmd}`);
371:       progress(`Cannot build from source: '${cmd}' not found. Install it and retry.\n`);

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


128. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/model-engine.ts:380
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

378:   for (const cc of ["g++", "c++", "clang++"]) {
379:     try {
380:       execSync(`which ${cc}`, { stdio: "pipe", timeout: 5000 });
381:       hasCompiler = true;
382:       break;
383:     } catch {

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


129. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/model-engine.ts:451
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

449: 
450:     progress(`Compiling llama.cpp (${nproc} cores, ${archDisplay})... this may take a few minutes`);
451:     execSync(`cmake --build build --config Release -j${nproc}`, {
452:       cwd: repoDir,
453:       stdio: "pipe",
454:       timeout: 600000, // 10 minutes max

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


130. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/model-engine.ts:466
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

464:     // Copy to engine directory
465:     const destBin = join(ENGINE_DIR, "llama-server");
466:     execSync(`cp "${builtBin}" "${destBin}"`, { stdio: "pipe" });
467:     chmodSync(destBin, 0o755);
468: 
469:     // Copy shared libraries from build

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


131. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/model-engine.ts:479
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

477:         if (!existsSync(dest)) {
478:           try {
479:             execSync(`cp "${libPath}" "${dest}"`, { stdio: "pipe" });
480:           } catch {
481:             /* non-fatal */
482:           }

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


132. 🔴 child_process.exec / spawn / execFile of a tainted expression (taint-lite) — CWE-78

File: src/core/model-file-utils.ts:348
Severity: CRITICAL
Pattern: js-ast-006-exec-of-tainted-expression

Why this matters:
child_process.exec / spawn / execFile with a command string the taint walker traces back to an external source. js-ast-002 catches the bare-parameter case; this catches concat ('ls ' + userPath) and assignment-propagated taint patterns that regex misses.

Code:

.spawnSync([whichCmd, "kcode"])  // command string is tainted from req/request/process/ctx/document/location (possibly via assignment + concat)

Verification: Verification skipped — static-only mode

Fix template: Use execFile/spawn with the args array form and a hardcoded command, then shell-escape every tainted argv entry. Never build the shell command via string concat with external input.


133. 🔴 child_process.exec / spawn / execFile of a tainted expression (taint-lite) — CWE-78

File: src/core/offline/local-search.ts:252
Severity: CRITICAL
Pattern: js-ast-006-exec-of-tainted-expression

Why this matters:
child_process.exec / spawn / execFile with a command string the taint walker traces back to an external source. js-ast-002 catches the bare-parameter case; this catches concat ('ls ' + userPath) and assignment-propagated taint patterns that regex misses.

Code:

.spawnSync(["apropos", query])  // command string is tainted from req/request/process/ctx/document/location (possibly via assignment + concat)

Verification: Verification skipped — static-only mode

Fix template: Use execFile/spawn with the args array form and a hardcoded command, then shell-escape every tainted argv entry. Never build the shell command via string concat with external input.


134. 🔴 child_process.exec / spawn / execFile of a tainted expression (taint-lite) — CWE-78

File: src/core/plugin-sdk/sandbox.ts:233
Severity: CRITICAL
Pattern: js-ast-006-exec-of-tainted-expression

Why this matters:
child_process.exec / spawn / execFile with a command string the taint walker traces back to an external source. js-ast-002 catches the bare-parameter case; this catches concat ('ls ' + userPath) and assignment-propagated taint patterns that regex misses.

Code:

.spawnSync([command, ...args])  // command string is tainted from req/request/process/ctx/document/location (possibly via assignment + concat)

Verification: Verification skipped — static-only mode

Fix template: Use execFile/spawn with the args array form and a hardcoded command, then shell-escape every tainted argv entry. Never build the shell command via string concat with external input.


135. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/rag/chunker.ts:497
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


136. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/rag/chunker.ts:503
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(content)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


137. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/rag/vector-store.ts:45
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

43:   /** Create the rag_chunks table if it doesn't exist */
44:   private createSchema(): void {
45:     this.db.exec(`CREATE TABLE IF NOT EXISTS rag_chunks (
46:       id TEXT PRIMARY KEY,
47:       file_path TEXT NOT NULL,
48:       relative_path TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


138. 🔴 Shell command with template literal (injection) — CWE-78

File: src/core/rag/vector-store.ts:251
Severity: CRITICAL
Pattern: js-007-command-injection

Why this matters:
Running shell commands with template literals allows injection if any interpolated value is user-controlled.

Code:

249: 
250:   private initSchema(): void {
251:     this.db.exec(`
252:       CREATE TABLE IF NOT EXISTS rag_vectors (
253:         id INTEGER PRIMARY KEY AUTOINCREMENT,
254:         filepath TEXT NOT NULL,

Verification: Verification skipped — static-only mode

Fix template: Use spawn/execFile with array args instead of shell string.


139. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/rate-limiter.ts:94
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(resolve)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


140. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/reference-extractor.ts:179
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(line)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


141. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78

File: src/core/reference-extractor.ts:195
Severity: CRITICAL
Pattern: js-ast-002-child-process-exec-of-parameter

Why this matters:
child_process.exec / execSync / spawn / execFile invoked with a value that AST analysis traces back to a function parameter. exec and execSync go through a shell, so any caller-controlled string is a command-injection candidate. spawn/execFile without shell:true are safer but still flagged because the parameter typically becomes the binary path or argv[0].

Code:

.exec(line)  // arg is a parameter of the enclosing function

Verification: Verification skipped — static-only mode

Fix template: Use execFile(binary, [arg1, arg2]) with hardcoded binary, or spawn() without shell:true. Validate the parameter against an allowlist before use. Never pass caller-controlled strings to exec / execSync.


142. 🔴 os.system / os.popen / exec with concatenated user input — CWE-78

File: src/core/session/teleport.ts:51
Severity: CRITICAL
Pattern: inj-003-os-system-with-var

Why this matters:
Passing a concatenated command to system/exec/popen is command injection, same class as shell=True but without the flag. Every unescaped shell metacharacter is an RCE vector.

Code:

49:   if (options.includeGitDiff) {
50:     try {
51:       const proc = Bun.spawn(["git", "diff", "--cached", "--diff-filter=ACMR"], {
52:         cwd: session.workingDirectory,
53:         stdout: "pipe",
54:         stderr: "pipe",

Verification: Verification skipped — static-only mode

Fix template: Use the list-argument form (execv, spawn with args array). For shells, escape with shlex.quote (Python) or shell-quote (Node).


143. 🔴 os.system / os.popen / exec with concatenated user input — CWE-78

File: src/core/session/teleport.ts:60
Severity: CRITICAL
Pattern: inj-003-os-system-with-var

Why this matters:
Passing a concatenated command to system/exec/popen is command injection, same class as shell=True but without the flag. Every unescaped shell metacharacter is an RCE vector.

Code:

58:       if (!gitDiff.trim()) {
59:         // Try unstaged diff
60:         const proc2 = Bun.spawn(["git", "diff"], {
61:           cwd: session.workingDirectory,
62:           stdout: "pipe",
63:           stderr: "pipe",

Verification: Verification skipped — static-only mode

Fix template: Use the list-argument form (execv, spawn with args array). For shells, escape with shlex.quote (Python) or shell-quote (Node).


144. 🔴 eval / Function / setTimeout(string) of a tainted expression (taint-lite) — CWE-95

File: src/core/setup-wizard.ts:202
Severity: CRITICAL
Pattern: js-ast-005-eval-of-tainted-expression

Why this matters:
eval / Function / setTimeout-string with an argument the taint walker traces back to an external source (HTTP request, process.argv, process.env, document, location) — possibly through an intermediate const x = req.body style assignment. js-ast-001 catches the parameter case; this catches the assignment + member-access cases the regex pattern can't prove.

Code:

setInterval(() => {
      if (stopped) return;
      const spinner = `${C.cyan}${spinnerF…)  // expression is tainted (member access / assignment / concat from req/request/process/ctx/document/location)

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a dispatch table for command names, or a parser that validates structure before use. Concatenation does not sanitize.


145. 🔴 eval / Function / setTimeout(string) of a function parameter (taint via AST) — CWE-95

File: src/core/setup-wizard.ts:914
Severity: CRITICAL
Pattern: js-ast-001-eval-of-parameter

Why this matters:
eval, Function, or a string-form setTimeout/setInterval invoked with an argument that AST analysis traces back to a function parameter. The regex form catches the call but can't prove the argument flows from caller-controlled input. AST resolves the chain.

Code:

setTimeout(r)  // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as code

Verification: Verification skipped — static-only mode

Fix template: Replace eval(x) with JSON.parse(x) for data, a Map/Object lookup for dispatch, or schema-validated input. Never eval a value the caller controls.


146. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: backend/src/keys.ts:22
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

20:  */
21: export function generateProKey(customerId: string): string {
22:   const customerHash = createHash("sha256").update(customerId).digest("hex").slice(0, 12);
23:   const entropy = randomBytes(16).toString("hex");
24:   const body = `${customerHash}${entropy}`;
25:   const checksum = createHash("sha256").update(body).digest("hex").slice(0, CHECKSUM_LEN);

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


147. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: backend/src/keys.ts:25
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

23:   const entropy = randomBytes(16).toString("hex");
24:   const body = `${customerHash}${entropy}`;
25:   const checksum = createHash("sha256").update(body).digest("hex").slice(0, CHECKSUM_LEN);
26:   return `kcode_pro_${body}${checksum}`;
27: }
28: 

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


148. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: backend/src/keys.ts:37
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

35:   const expiryEpoch = Math.floor(Date.now() / 1000) + daysValid * 24 * 60 * 60;
36:   const body = `${random}_${expiryEpoch}`;
37:   const checksum = createHash("sha256").update(body).digest("hex").slice(0, CHECKSUM_LEN);
38:   return `kcode_trial_${body}${checksum}`;
39: }
40: 

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


149. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: backend/src/keys.ts:61
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

59:     const body = payload.slice(0, -len);
60:     const check = payload.slice(-len).toLowerCase();
61:     const expected = createHash("sha256").update(body).digest("hex").slice(0, len);
62:     if (check === expected) return true;
63:   }
64:   return false;

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


150. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: backend/src/stripe.ts:32
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

30:   }
31: 
32:   const resp = await fetch(url, options);
33:   const body = (await resp.json()) as Record<string, unknown>;
34: 
35:   if (!resp.ok) {

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


151. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: ide/vscode/src/api-client.ts:138
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

136:   private async fetch<T>(path: string, options?: RequestInit): Promise<T> {
137:     const url = `${this.baseUrl}${path}`;
138:     const resp = await fetch(url, {
139:       ...options,
140:       headers: { ...this.headers(), ...options?.headers },
141:     });

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


152. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: ide/vscode/src/api-client.ts:183
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

181:     const url = `${this.baseUrl}/api/prompt`;
182: 
183:     const resp = await fetch(url, {
184:       method: "POST",
185:       headers: this.headers(),
186:       body: JSON.stringify({ prompt, stream: true }),

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


153. 🟠 Object merge / assign from user input without proto guard — CWE-1321

File: sdk/typescript/src/index.ts:98
Severity: HIGH
Pattern: inj-012-proto-pollution

Why this matters:
Merging a user-provided object into a target without filtering __proto__ or constructor.prototype keys pollutes Object.prototype globally, leading to RCE in subsequent code paths. Jest, Mongoose, Kibana all had this class of CVE.

Code:

96:     }
97:     if (extra) {
98:       Object.assign(h, extra);
99:     }
100:     return h;
101:   }

Verification: Verification skipped — static-only mode

Fix template: Use Object.create(null) for the target, or deny-list __proto__/constructor/prototype keys. Prefer immutable merge ({ ...a, ...b } is shallow-safe).


154. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: sdk/typescript/src/index.ts:113
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

111: 
112:     try {
113:       const res = await fetch(`${this.baseUrl}${path}`, {
114:         method,
115:         headers: this.headers(extraHeaders),
116:         body: body !== undefined ? JSON.stringify(body) : undefined,

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


155. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: sdk/typescript/src/index.ts:113
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

111: 
112:     try {
113:       const res = await fetch(`${this.baseUrl}${path}`, {
114:         method,
115:         headers: this.headers(extraHeaders),
116:         body: body !== undefined ? JSON.stringify(body) : undefined,

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


156. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: sdk/typescript/src/index.ts:191
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

189: 
190:     try {
191:       const res = await fetch(`${this.baseUrl}/api/prompt`, {
192:         method: "POST",
193:         headers,
194:         body: JSON.stringify({

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


157. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: sdk/typescript/src/index.ts:191
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

189: 
190:     try {
191:       const res = await fetch(`${this.baseUrl}/api/prompt`, {
192:         method: "POST",
193:         headers,
194:         body: JSON.stringify({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


158. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/cli/commands/benchmark.ts:21
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

19: 
20:       try {
21:         const resp = await fetch(`${baseUrl}/v1/chat/completions`, {
22:           method: "POST",
23:           headers: {
24:             "Content-Type": "application/json",

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


159. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/cli/commands/benchmark.ts:21
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

19: 
20:       try {
21:         const resp = await fetch(`${baseUrl}/v1/chat/completions`, {
22:           method: "POST",
23:           headers: {
24:             "Content-Type": "application/json",

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


160. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/cli/commands/mcp.ts:99
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

97:       if (args.length > 0) entry.args = args;
98: 
99:       data.mcpServers[name] = entry;
100: 
101:       // Ensure directory exists
102:       const { mkdirSync } = await import("node:fs");

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


161. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/cli/commands/models.ts:230
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

228: 
229:       try {
230:         const response = await fetch(`${baseUrl}/v1/chat/completions`, {
231:           method: "POST",
232:           headers: { "Content-Type": "application/json" },
233:           body: JSON.stringify({

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


162. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/cli/commands/models.ts:230
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

228: 
229:       try {
230:         const response = await fetch(`${baseUrl}/v1/chat/completions`, {
231:           method: "POST",
232:           headers: { "Content-Type": "application/json" },
233:           body: JSON.stringify({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


163. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/cli/commands/plugin-sdk/publish.ts:39
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

37:   }
38: 
39:   const response = await fetch(`${registryUrl}/plugins`, {
40:     method: "POST",
41:     headers: {
42:       "Content-Type": "application/octet-stream",

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


164. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/cli/commands/plugin-sdk/publish.ts:39
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

37:   }
38: 
39:   const response = await fetch(`${registryUrl}/plugins`, {
40:     method: "POST",
41:     headers: {
42:       "Content-Type": "application/octet-stream",

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


165. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/cli/commands/template.ts:97
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

95:           const value = rawArgs[i + 1];
96:           if (value && !value.startsWith("--")) {
97:             params[key] = value === "true" ? true : value === "false" ? false : value;
98:             i++;
99:           } else {
100:             params[key] = true;

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


166. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/cli/commands/template.ts:100
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

98:             i++;
99:           } else {
100:             params[key] = true;
101:           }
102:         }
103:       }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


167. 🟠 Object merge / assign from user input without proto guard — CWE-1321

File: src/cli/commands/template.ts:114
Severity: HIGH
Pattern: inj-012-proto-pollution

Why this matters:
Merging a user-provided object into a target without filtering __proto__ or constructor.prototype keys pollutes Object.prototype globally, leading to RCE in subsequent code paths. Jest, Mongoose, Kibana all had this class of CVE.

Code:

112:           parameters: missing,
113:         });
114:         Object.assign(params, interactive);
115:       }
116: 
117:       // Dry run

Verification: Verification skipped — static-only mode

Fix template: Use Object.create(null) for the target, or deny-list __proto__/constructor/prototype keys. Prefer immutable merge ({ ...a, ...b } is shallow-safe).


168. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/agents/executor.ts:169
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

167:   let response: Response;
168:   try {
169:     response = await fetch(url, {
170:       method: "POST",
171:       headers: auth.headers,
172:       body: JSON.stringify(body),

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


169. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/audit-engine/audit-history.ts:103
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

101: export function snippetHash(pattern_id: string, matched_text: string): string {
102:   const normalized = matched_text.replace(/\s+/g, "");
103:   return createHash("sha256").update(`${pattern_id}|${normalized}`).digest("hex").slice(0, 16);
104: }
105: 
106: /**

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


170. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/audit-engine/llm-callback.ts:134
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

132:     ): Promise<Response> => {
133:       for (let attempt = 0; attempt <= maxRetries; attempt++) {
134:         const res = await fetch(url, init);
135:         if (res.status === 429 && attempt < maxRetries) {
136:           const retryAfter = parseInt(res.headers.get("retry-after") ?? "5", 10);
137:           const delay = Math.min(retryAfter * 1000, 15000) * (attempt + 1);

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


171. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/audit-engine/llm-callback.ts:143
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

141:         return res;
142:       }
143:       return fetch(url, init); // final attempt
144:     };
145: 
146:     if (isAnthropic) {

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


172. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/audit-engine/sarif-exporter.ts:52
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

50: function fingerprintFinding(f: Finding): string {
51:   const material = [f.pattern_id, f.file, f.line, f.matched_text.trim()].join("\x1f");
52:   return createHash("sha256").update(material).digest("hex").slice(0, 32);
53: }
54: 
55: /**

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


173. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/auth/claude-code-bridge.ts:123
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

121: 
122:   try {
123:     const response = await fetch(ANTHROPIC_TOKEN_URL, {
124:       method: "POST",
125:       headers: { "Content-Type": "application/x-www-form-urlencoded" },
126:       body: new URLSearchParams({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


174. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/auth/claude-code-bridge.ts:214
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

212: 
213:   try {
214:     const response = await fetch(OPENAI_TOKEN_URL, {
215:       method: "POST",
216:       headers: { "Content-Type": "application/x-www-form-urlencoded" },
217:       body: new URLSearchParams({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


175. 🟠 obj[key] = ... where key is a function parameter (prototype pollution candidate) — CWE-1321

File: src/core/auth/keychain.ts:226
Severity: HIGH
Pattern: ts-ast-001-prototype-pollution-of-parameter

Why this matters:
Assignment to obj[key] where AST analysis traces key back to a function parameter. If the function is exposed and the caller controls key, they can set obj.proto, obj.constructor, or obj.prototype, which (depending on usage downstream) can let them inject properties into Object.prototype itself. Common in helper functions like merge(target, key, value) and set(o, k, v) that sit underneath Lodash-like APIs.

Code:

entries[account] = ...  // key is a parameter — attacker can pass "__proto__" / "constructor"

Verification: Verification skipped — static-only mode

Fix template: Reject the dangerous keys before assigning: if (key === "__proto__" || key === "constructor" || key === "prototype") return;. Better: use Object.defineProperty(target, key, { value, enumerable: true, writable: true, configurable: true }), or use Map.set when the underlying type allows it.


176. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/auth/oauth-flow.ts:284
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

282:   redirectUri: string,
283: ): Promise<OAuthTokens> {
284:   const response = await fetch(config.tokenUrl, {
285:     method: "POST",
286:     headers: { "Content-Type": "application/x-www-form-urlencoded" },
287:     body: new URLSearchParams({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


177. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/auth/oauth-flow.ts:340
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

338:   refreshToken: string,
339: ): Promise<OAuthTokens> {
340:   const response = await fetch(config.tokenUrl, {
341:     method: "POST",
342:     headers: { "Content-Type": "application/x-www-form-urlencoded" },
343:     body: new URLSearchParams({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


178. 🟠 Session ID not regenerated after authentication — CWE-384

File: src/core/auth/oauth-flow.ts:474
Severity: HIGH
Pattern: uni-013-session-fixation

Why this matters:
After successful authentication, the session ID must be regenerated. Otherwise, an attacker who fixed the session ID before login can hijack the authenticated session.

Code:

472:  * Returns { provider, method: "oauth" | "api_key", key?: string }
473:  */
474: export async function loginProvider(
475:   providerName: string,
476:   opts?: { onAuthUrl?: (url: string) => void },
477: ): Promise<{

Verification: Verification skipped — static-only mode

Fix template: Call session regeneration immediately after successful authentication: req.session.regenerate() (Express), request.session.cycle_key() (Django), session_regenerate_id(true) (PHP).


179. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/auto-agents.ts:164
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

162:       for (const [key, value] of Object.entries(process.env)) {
163:         if (value !== undefined && AGENT_ENV_ALLOWLIST.has(key)) {
164:           env[key] = value;
165:         }
166:       }
167:       // Inject credentials from the parent session's config

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


180. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/bash-spawn-verifier.ts:245
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

243: 
244:   try {
245:     const resp = await fetch(url, {
246:       method: "GET",
247:       signal: AbortSignal.timeout(timeoutMs),
248:     });

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


181. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/cloud/client.ts:110
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

108:     const baseUrl = this.config?.url ?? DEFAULT_CLOUD_URL;
109: 
110:     const response = await fetch(`${baseUrl}/api/v1/auth/login`, {
111:       method: "POST",
112:       headers: { "Content-Type": "application/json" },
113:       body: JSON.stringify({ email, password }),

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


182. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/cloud/client.ts:110
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

108:     const baseUrl = this.config?.url ?? DEFAULT_CLOUD_URL;
109: 
110:     const response = await fetch(`${baseUrl}/api/v1/auth/login`, {
111:       method: "POST",
112:       headers: { "Content-Type": "application/json" },
113:       body: JSON.stringify({ email, password }),

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


183. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/cloud/client.ts:226
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

224:     let response: Response;
225:     try {
226:       response = await fetch(url, init);
227:     } catch (err) {
228:       throw new Error(
229:         `Cloud API request failed: unable to connect to ${config.url}. ` +

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


184. 🟠 Authentication credential compared with == instead of constant-time comparison — CWE-287

File: src/core/collab/session-share.ts:62
Severity: HIGH
Pattern: uni-005-weak-auth-compare

Why this matters:
Comparing authentication credentials with == or === is vulnerable to timing side-channel attacks. An attacker can determine the correct credential one character at a time by measuring response time differences.

Code:

60:   join(token: string, name: string): JoinResult {
61:     if (!this.session) throw new Error("No active sharing session");
62:     if (token !== this.session.shareToken) throw new Error("Invalid share token");
63:     if (this.session.participants.length >= this.session.maxParticipants) {
64:       throw new Error("Session is full");
65:     }

Verification: Verification skipped — static-only mode

Fix template: Use constant-time comparison: hmac.compare_digest() (Python), crypto.timingSafeEqual() (Node.js), subtle.ConstantTimeCompare() (Go).


185. 🟠 String equality (==, strcmp, ===) used on MAC / HMAC / token — CWE-208

File: src/core/collab/session-share.ts:62
Severity: HIGH
Pattern: crypto-005-timing-safe-compare-missing

Why this matters:
Comparing a MAC / HMAC / signature with regular equality leaks length and match progress via timing. An attacker can recover the correct MAC byte-by-byte from timing side channels. CVE-2011-4121 (OpenSSL), CVE-2014-0160 (Heartbleed's adjacent class).

Code:

60:   join(token: string, name: string): JoinResult {
61:     if (!this.session) throw new Error("No active sharing session");
62:     if (token !== this.session.shareToken) throw new Error("Invalid share token");
63:     if (this.session.participants.length >= this.session.maxParticipants) {
64:       throw new Error("Session is full");
65:     }

Verification: Verification skipped — static-only mode

Fix template: Python: hmac.compare_digest. Node: crypto.timingSafeEqual. Go: subtle.ConstantTimeCompare. Java: MessageDigest.isEqual. C: CRYPTO_memcmp. PHP: hash_equals.


186. 🟠 Authentication credential compared with == instead of constant-time comparison — CWE-287

File: src/core/config.ts:224
Severity: HIGH
Pattern: uni-005-weak-auth-compare

Why this matters:
Comparing authentication credentials with == or === is vulnerable to timing side-channel attacks. An attacker can determine the correct credential one character at a time by measuring response time differences.

Code:

222:           : undefined,
223:     effortLevel: isEffortLevel(raw.effortLevel) ? raw.effortLevel : undefined,
224:     apiKey: typeof raw.apiKey === "string" ? raw.apiKey : undefined,
225:     anthropicApiKey: typeof raw.anthropicApiKey === "string" ? raw.anthropicApiKey : undefined,
226:     xaiApiKey: typeof raw.xaiApiKey === "string" ? raw.xaiApiKey : undefined,
227:     groqApiKey: typeof raw.groqApiKey === "string" ? raw.groqApiKey : undefined,

Verification: Verification skipped — static-only mode

Fix template: Use constant-time comparison: hmac.compare_digest() (Python), crypto.timingSafeEqual() (Node.js), subtle.ConstantTimeCompare() (Go).


187. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:137
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

135: 
136:       if (isArray) {
137:         meta[key] = collected.filter(Boolean);
138:       } else if (collected.length > 0) {
139:         // Try parsing as JSON (for mcpServers, hooks)
140:         const joined = collected.join("\n");

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


188. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:143
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

141:         if (joined.length > 100 * 1024) continue; // Skip JSON > 100KB
142:         try {
143:           meta[key] = JSON.parse(joined);
144:         } catch {
145:           meta[key] = joined;
146:         }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


189. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:145
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

143:           meta[key] = JSON.parse(joined);
144:         } catch {
145:           meta[key] = joined;
146:         }
147:       }
148:       continue;

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


190. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:154
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

152:     if (rawValue.startsWith("{") || (rawValue.startsWith("[") && rawValue.includes("{"))) {
153:       try {
154:         meta[key] = JSON.parse(rawValue);
155:         continue;
156:       } catch {
157:         // Fall through to normal parsing

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


191. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:163
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

161:     // Inline array: [item1, item2]
162:     if (rawValue.startsWith("[") && rawValue.endsWith("]")) {
163:       meta[key] = rawValue
164:         .slice(1, -1)
165:         .split(",")
166:         .map((s) => s.trim().replace(/^["']|["']$/g, ""))

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


192. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:173
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

171:     // Parse booleans
172:     if (rawValue === "true") {
173:       meta[key] = true;
174:       continue;
175:     }
176:     if (rawValue === "false") {

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


193. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:177
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

175:     }
176:     if (rawValue === "false") {
177:       meta[key] = false;
178:       continue;
179:     }
180: 

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


194. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:184
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

182:     const num = Number(rawValue);
183:     if (rawValue !== "" && !isNaN(num)) {
184:       meta[key] = num;
185:       continue;
186:     }
187: 

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


195. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:196
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

194:     }
195: 
196:     meta[key] = rawValue;
197:   }
198: 
199:   return { meta, body };

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


196. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/custom-agents.ts:243
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

241:     if (!config || typeof config !== "object") continue;
242:     const c = config as Record<string, unknown>;
243:     result[name] = {
244:       command: typeof c.command === "string" ? c.command : undefined,
245:       args: Array.isArray(c.args) ? c.args.map(String) : undefined,
246:       env: c.env && typeof c.env === "object" ? (c.env as Record<string, string>) : undefined,

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


197. 🟠 Authentication credential compared with == instead of constant-time comparison — CWE-287

File: src/core/custom-agents.ts:306
Severity: HIGH
Pattern: uni-005-weak-auth-compare

Why this matters:
Comparing authentication credentials with == or === is vulnerable to timing side-channel attacks. An attacker can determine the correct credential one character at a time by measuring response time differences.

Code:

304:   const apiKey = isProjectLevel
305:     ? undefined
306:     : typeof meta.apiKey === "string" && validateEnvValue(meta.apiKey)
307:       ? meta.apiKey
308:       : undefined;
309:   const apiBase = isProjectLevel ? undefined : validateApiBase(meta.apiBase);

Verification: Verification skipped — static-only mode

Fix template: Use constant-time comparison: hmac.compare_digest() (Python), crypto.timingSafeEqual() (Node.js), subtle.ConstantTimeCompare() (Go).


198. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/distillation/evaluator.ts:276
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

274:     const apiBase = config.apiBase ?? DEFAULT_API_BASE;
275: 
276:     const resp = await fetch(`${apiBase}/v1/chat/completions`, {
277:       method: "POST",
278:       headers: { "Content-Type": "application/json" },
279:       body: JSON.stringify({

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


199. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/doctor.ts:151
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

149:     const controller = new AbortController();
150:     const timeout = setTimeout(() => controller.abort(), 5000);
151:     const response = await fetch(`${baseUrl}/v1/models`, { signal: controller.signal });
152:     clearTimeout(timeout);
153:     if (response.ok) {
154:       results.push({

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


200. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/doctor.ts:151
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

149:     const controller = new AbortController();
150:     const timeout = setTimeout(() => controller.abort(), 5000);
151:     const response = await fetch(`${baseUrl}/v1/models`, { signal: controller.signal });
152:     clearTimeout(timeout);
153:     if (response.ok) {
154:       results.push({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


201. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/doctor/checks/network-check.ts:16
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

14:     const timeout = setTimeout(() => controller.abort(), 5000);
15: 
16:     const response = await fetch(`${baseUrl}/v1/models`, { signal: controller.signal });
17:     clearTimeout(timeout);
18:     const latency = Date.now() - start;
19: 

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


202. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/doctor/checks/network-check.ts:16
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

14:     const timeout = setTimeout(() => controller.abort(), 5000);
15: 
16:     const response = await fetch(`${baseUrl}/v1/models`, { signal: controller.signal });
17:     clearTimeout(timeout);
18:     const latency = Date.now() - start;
19: 

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


203. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/doctor/provider-probe.ts:177
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

175:   const start = Date.now();
176:   try {
177:     const resp = await fetch(prov.modelsUrl, {
178:       method: "GET",
179:       headers: buildAuthHeaders(prov, key),
180:       signal: AbortSignal.timeout(10_000),

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


204. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/doctor/provider-probe.ts:220
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

218:         };
219:   try {
220:     const resp = await fetch(prov.completionsUrl, {
221:       method: "POST",
222:       headers: buildAuthHeaders(prov, key),
223:       body: JSON.stringify(body),

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


205. 🟠 Object merge / assign from user input without proto guard — CWE-1321

File: src/core/dream/dream-engine.ts:186
Severity: HIGH
Pattern: inj-012-proto-pollution

Why this matters:
Merging a user-provided object into a target without filtering __proto__ or constructor.prototype keys pollutes Object.prototype globally, leading to RCE in subsequent code paths. Jest, Mongoose, Kibana all had this class of CVE.

Code:

184:    */
185:   updateState(partial: Partial<DreamState>): void {
186:     Object.assign(this.state, partial);
187:   }
188: 
189:   /**

Verification: Verification skipped — static-only mode

Fix template: Use Object.create(null) for the target, or deny-list __proto__/constructor/prototype keys. Prefer immutable merge ({ ...a, ...b } is shallow-safe).


206. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/enterprise/sso.ts:246
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

244:     : Date.now() + 8 * 60 * 60 * 1000; // Default: 8 hours
245: 
246:   const userId = createHash("sha256").update(email.toLowerCase()).digest("hex").slice(0, 16);
247: 
248:   const session: SSOSession = {
249:     userId,

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


207. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/enterprise/sso.ts:397
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

395:     }
396: 
397:     const userId = createHash("sha256").update(email.toLowerCase()).digest("hex").slice(0, 16);
398: 
399:     const session: SSOSession = {
400:       userId,

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


208. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/feature-flags.ts:56
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

54:   if (settingsFlags) {
55:     for (const key of Object.keys(flags) as (keyof RuntimeFeatureFlags)[]) {
56:       if (key in settingsFlags && typeof settingsFlags[key] === "boolean") {
57:         flags[key] = settingsFlags[key] as boolean;
58:       }
59:     }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


209. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/feature-flags.ts:57
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

55:     for (const key of Object.keys(flags) as (keyof RuntimeFeatureFlags)[]) {
56:       if (key in settingsFlags && typeof settingsFlags[key] === "boolean") {
57:         flags[key] = settingsFlags[key] as boolean;
58:       }
59:     }
60:   }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


210. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/feature-flags.ts:67
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

65:     const envVal = process.env[envName];
66:     if (envVal !== undefined) {
67:       flags[key] = envVal === "true" || envVal === "1";
68:     }
69:   }
70: 

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


211. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/file-edit-history.ts:62
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

60:     payload = String(input.content ?? "");
61:   }
62:   const hash = createHash("sha1").update(payload).digest("hex").slice(0, 16);
63:   return `${toolName}|${filePath}|${hash}`;
64: }
65: 

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


212. 🟠 new RegExp(p) / RegExp(p) where p is a function parameter (ReDoS sink) — CWE-1333

File: src/core/hook-executor.ts:70
Severity: HIGH
Pattern: js-ast-003-regexp-construction-of-parameter

Why this matters:
RegExp built from a value that AST analysis traces back to a function parameter. A caller-controlled regex source can trigger catastrophic backtracking on benign-looking inputs (e.g. (a+)+$ against a long matching prefix). Even when the regex isn't pathological, accepting raw regex from a caller leaks the ability to enumerate or fingerprint internal data via crafted patterns.

Code:

RegExp(pattern)  // arg is a parameter — caller-controlled regex source is a ReDoS sink

Verification: Verification skipped — static-only mode

Fix template: Either (a) escape the parameter with a regex-escape helper before passing it to RegExp, (b) use String.prototype.includes / indexOf if substring containment is what you need, or (c) bound the input length and reject regex-like control characters.


213. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/hookify.ts:109
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

107:       // Safe: `key` guaranteed not in {__proto__, constructor, prototype}
108:       // by the RESERVED_META_KEYS guard above.
109:       meta[key] = parseYamlValue(value);
110:     }
111:   }
112: 

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


214. 🟠 File operation following symlinks without resolution check (TOCTOU) — CWE-59

File: src/core/kulvex-discovery.ts:42
Severity: HIGH
Pattern: uni-015-symlink-toctou

Why this matters:
Check-then-use patterns on files are vulnerable to TOCTOU attacks via symlinks. Between the check (exists/stat/access) and the use (open/read/write), an attacker can replace the file with a symlink pointing to a sensitive location.

Code:

40:     const os = require("node:os") as typeof import("node:os");
41:     const file = path.join(os.homedir(), ".kcode", "settings.json");
42:     if (fs.existsSync(file)) {
43:       const cfg = JSON.parse(fs.readFileSync(file, "utf-8")) as {
44:         kulvex?: { discover?: boolean; endpoints?: string[] };
45:       };

Verification: Verification skipped — static-only mode

Fix template: Use atomic operations (openat with O_NOFOLLOW, fstat on the open fd, realpath + prefix check).


215. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/kulvex-discovery.ts:67
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

65:   const controller = AbortSignal.timeout(1000);
66:   try {
67:     const resp = await fetch(`${baseUrl}/v1/models`, { signal: controller });
68:     if (!resp.ok) return null;
69:     const body = (await resp.json()) as { data?: Array<{ id?: string; object?: string }> };
70:     const first = body.data?.[0];

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


216. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/kulvex-discovery.ts:67
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

65:   const controller = AbortSignal.timeout(1000);
66:   try {
67:     const resp = await fetch(`${baseUrl}/v1/models`, { signal: controller });
68:     if (!resp.ok) return null;
69:     const body = (await resp.json()) as { data?: Array<{ id?: string; object?: string }> };
70:     const first = body.data?.[0];

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


217. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/kulvex-discovery.ts:77
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

75:     let backend: KulvexEndpoint["backend"] = "unknown";
76:     try {
77:       const health = await fetch(`${baseUrl}/health`, { signal: AbortSignal.timeout(500) });
78:       if (health.ok) {
79:         const text = await health.text();
80:         if (/llama|metal/i.test(text)) backend = "llama.cpp";

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


218. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/kulvex-discovery.ts:77
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

75:     let backend: KulvexEndpoint["backend"] = "unknown";
76:     try {
77:       const health = await fetch(`${baseUrl}/health`, { signal: AbortSignal.timeout(500) });
78:       if (health.ok) {
79:         const text = await health.text();
80:         if (/llama|metal/i.test(text)) backend = "llama.cpp";

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


219. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/marketplace.ts:307
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

305:     }
306: 
307:     config.installed[name] = {
308:       version: plugin.version,
309:       installedAt: new Date().toISOString(),
310:     };

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


220. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/marketplace.ts:350
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

348:   cpSync(result.pluginDir, pluginDir, { recursive: true });
349: 
350:   config.installed[name] = {
351:     version: result.version,
352:     installedAt: new Date().toISOString(),
353:     marketplace: cdnSource.name,

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


221. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/marketplace.ts:390
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

388:     if (plugin) {
389:       const config = loadConfig();
390:       config.installed[name] = {
391:         version: plugin.version,
392:         installedAt: config.installed[name]?.installedAt ?? new Date().toISOString(),
393:       };

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


222. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/marketplace/auto-updater.ts:180
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

178:     : `https://plugins.kulvex.ai/api/v1/${marketplace}/catalog`;
179: 
180:   const resp = await fetch(url, { signal: AbortSignal.timeout(10_000) });
181:   if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
182:   return (await resp.json()) as CatalogEntry[];
183: }

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


223. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/marketplace/cdn-fetcher.ts:71
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

69:       const tarballPath = join(downloadTmpDir, "plugin.tar.gz");
70: 
71:       const response = await fetch(tarballUrl, {
72:         signal: AbortSignal.timeout(this.config.timeoutMs),
73:       });
74: 

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


224. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/marketplace/output-style-loader.ts:122
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

120:     if (value === "false") value = false;
121: 
122:     if (key) frontmatter[key] = value;
123:   }
124: 
125:   return { frontmatter, content };

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


225. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-client.ts:133
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

131:     if (DANGEROUS_KEYS.has(key)) continue;
132:     if (typeof value === "string" && value.length > MAX_STRING_FIELD_SIZE) {
133:       result[key] =
134:         value.slice(0, MAX_STRING_FIELD_SIZE) + `\n[Truncated at ${MAX_STRING_FIELD_SIZE} bytes]`;
135:     } else if (value !== null && typeof value === "object" && !Array.isArray(value)) {
136:       result[key] = sanitizeMcpInput(value as Record<string, unknown>, depth + 1);

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


226. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-client.ts:136
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

134:         value.slice(0, MAX_STRING_FIELD_SIZE) + `\n[Truncated at ${MAX_STRING_FIELD_SIZE} bytes]`;
135:     } else if (value !== null && typeof value === "object" && !Array.isArray(value)) {
136:       result[key] = sanitizeMcpInput(value as Record<string, unknown>, depth + 1);
137:     } else if (Array.isArray(value)) {
138:       const capped = value.slice(0, MAX_ARRAY_ELEMENTS);
139:       result[key] = capped.map((item) =>

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


227. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-client.ts:139
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

137:     } else if (Array.isArray(value)) {
138:       const capped = value.slice(0, MAX_ARRAY_ELEMENTS);
139:       result[key] = capped.map((item) =>
140:         item !== null && typeof item === "object" && !Array.isArray(item)
141:           ? sanitizeMcpInput(item as Record<string, unknown>, depth + 1)
142:           : item,

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


228. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-client.ts:145
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

143:       );
144:     } else {
145:       result[key] = value;
146:     }
147:   }
148:   return result;

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


229. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-client.ts:288
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

286:     for (const [key, value] of Object.entries(process.env)) {
287:       if (value !== undefined && MCP_ENV_ALLOWLIST.has(key)) {
288:         filteredParentEnv[key] = value;
289:       }
290:     }
291:     const rawEnv = { ...filteredParentEnv, ...(this.config.env ?? {}) };

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


230. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-client.ts:722
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

720:         // Block header injection via newlines/control chars
721:         if (typeof value === "string" && !/[\r\n\0]/.test(value) && !/[\r\n\0]/.test(key)) {
722:           headers[key] = value;
723:         }
724:       }
725:     }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


231. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp-oauth.ts:201
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

199:   const data: Record<string, TokenStorageEntry> = {};
200:   for (const [key, entry] of store) {
201:     data[key] = {
202:       ...entry,
203:       tokens: encryptTokens(entry.tokens as OAuthTokens),
204:       encrypted: true,

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


232. 🟠 Authentication credential compared with == instead of constant-time comparison — CWE-287

File: src/core/mcp-oauth.ts:479
Severity: HIGH
Pattern: uni-005-weak-auth-compare

Why this matters:
Comparing authentication credentials with == or === is vulnerable to timing side-channel attacks. An attacker can determine the correct credential one character at a time by measuring response time differences.

Code:

477:     };
478: 
479:     if (typeof data.refresh_token === "string") {
480:       tokens.refreshToken = data.refresh_token;
481:     }
482: 

Verification: Verification skipped — static-only mode

Fix template: Use constant-time comparison: hmac.compare_digest() (Python), crypto.timingSafeEqual() (Node.js), subtle.ConstantTimeCompare() (Go).


233. 🟠 String equality (==, strcmp, ===) used on MAC / HMAC / token — CWE-208

File: src/core/mcp-oauth.ts:576
Severity: HIGH
Pattern: crypto-005-timing-safe-compare-missing

Why this matters:
Comparing a MAC / HMAC / signature with regular equality leaks length and match progress via timing. An attacker can recover the correct MAC byte-by-byte from timing side channels. CVE-2011-4121 (OpenSSL), CVE-2014-0160 (Heartbleed's adjacent class).

Code:

574:   async isAuthenticated(serverName: string): Promise<boolean> {
575:     const token = await this.getToken(serverName);
576:     return token !== null;
577:   }
578: }
579: 

Verification: Verification skipped — static-only mode

Fix template: Python: hmac.compare_digest. Node: crypto.timingSafeEqual. Go: subtle.ConstantTimeCompare. Java: MessageDigest.isEqual. C: CRYPTO_memcmp. PHP: hash_equals.


234. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp.ts:175
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

173:       if (UNSAFE_KEYS.has(name)) continue;
174:       if (isValidServerConfig(config)) {
175:         validated[name] = config as McpServerConfig;
176:       }
177:     }
178:     if (Object.keys(validated).length === 0) return;

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


235. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/mcp.ts:266
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

264:             for (const [name, config] of Object.entries(data.mcpServers)) {
265:               if (isValidServerConfig(config)) {
266:                 merged[name] = config as McpServerConfig;
267:               }
268:             }
269:           }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


236. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/memory.ts:43
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

41: 
42: function hashProjectPath(projectPath: string): string {
43:   return createHash("sha256").update(projectPath).digest("hex").slice(0, 16);
44: }
45: 
46: export function getMemoryDir(projectPath: string): string {

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


237. 🟠 Object merge / assign from user input without proto guard — CWE-1321

File: src/core/mesh/node.ts:302
Severity: HIGH
Pattern: inj-012-proto-pollution

Why this matters:
Merging a user-provided object into a target without filtering __proto__ or constructor.prototype keys pollutes Object.prototype globally, leading to RCE in subsequent code paths. Jest, Mongoose, Kibana all had this class of CVE.

Code:

300:    */
301:   updateCapabilities(caps: Partial<PeerCapabilities>): void {
302:     Object.assign(this.capabilities, caps);
303:   }
304: 
305:   /**

Verification: Verification skipped — static-only mode

Fix template: Use Object.create(null) for the target, or deny-list __proto__/constructor/prototype keys. Prefer immutable merge ({ ...a, ...b } is shallow-safe).


238. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/mesh/transport.ts:201
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

199: 
200:     try {
201:       const response = await fetch(url, {
202:         method: "POST",
203:         headers: buildAuthHeaders(this.config.teamToken),
204:         body,

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


239. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/mesh/transport.ts:230
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

228: 
229:     try {
230:       const response = await fetch(url, {
231:         method: "POST",
232:         headers: buildAuthHeaders(this.config.teamToken),
233:         body: JSON.stringify(result),

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


240. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/mesh/transport.ts:259
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

257: 
258:     try {
259:       const response = await fetch(url, {
260:         headers: buildAuthHeaders(this.config.teamToken),
261:         signal: controller.signal,
262:       });

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


241. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918

File: src/core/model-local-discovery.ts:66
Severity: HIGH
Pattern: uni-003-ssrf

Why this matters:
When user-controlled input is used as a URL in server-side HTTP requests, an attacker can make the server request internal resources (metadata endpoints, internal APIs, cloud provider credentials at 169.254.169.254).

Code:

64:     const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
65:     try {
66:       const res = await fetch(`${trimmed}/props`, { signal: controller.signal });
67:       if (res.ok) {
68:         const json = (await res.json()) as LlamaServerProps;
69:         if (typeof json.model_path === "string" && json.model_path.length > 0) {

Verification: Verification skipped — static-only mode

Fix template: Validate the URL against an allowlist of permitted hosts. Block private IP ranges (10.x, 172.16-31.x, 192.168.x, 169.254.x, localhost).


242. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/offline/cache-warmer.ts:80
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

78:     for (const ep of endpoints) {
79:       try {
80:         const resp = await fetch(ep.url, { signal: AbortSignal.timeout(3000) });
81:         if (resp.ok) {
82:           const data = await resp.text();
83:           const outPath = join(this.dirs.models, `${ep.name}.json`);

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


243. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/offline/cache-warmer.ts:98
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

96:     try {
97:       const registryUrl = "https://plugins.kulvex.ai/api/v1/plugins";
98:       const resp = await fetch(registryUrl, { signal: AbortSignal.timeout(5000) });
99:       if (resp.ok) {
100:         const data = await resp.text();
101:         const outPath = join(this.dirs.plugins, "catalog.json");

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


244. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/offline/network-guard.ts:76
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

74:   }
75: 
76:   return fetch(url, init);
77: }
78: 

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


245. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/payments.ts:367
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

365: 
366:   // Generate a deterministic prefix from customer ID (for server-side lookup)
367:   const customerHash = createHash("sha256").update(customerId).digest("hex").slice(0, 12);
368: 
369:   // Add random entropy
370:   const entropy = randomBytes(16).toString("hex");

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


246. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/payments.ts:378
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

376:   // matches backend/src/keys.ts. The checksum is not a security boundary —
377:   // real authorization is the server-side DB lookup.)
378:   const checksum = createHash("sha256").update(body).digest("hex").slice(0, 16);
379: 
380:   const proKey = `kcode_pro_${body}${checksum}`;
381: 

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


247. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/permissions/audit-log.ts:370
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

368: ): string {
369:   const data = `${timestamp}|${toolName}|${action}|${sessionId}`;
370:   return createHmac("sha256", HMAC_KEY).update(data).digest("hex").slice(0, 16);
371: }
372: 
373: /** Verify HMAC integrity of an audit entry */

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


248. 🟠 String equality (==, strcmp, ===) used on MAC / HMAC / token — CWE-208

File: src/core/permissions/audit-log.ts:377
Severity: HIGH
Pattern: crypto-005-timing-safe-compare-missing

Why this matters:
Comparing a MAC / HMAC / signature with regular equality leaks length and match progress via timing. An attacker can recover the correct MAC byte-by-byte from timing side channels. CVE-2011-4121 (OpenSSL), CVE-2014-0160 (Heartbleed's adjacent class).

Code:

375:   if (!entry.hmac) return false;
376:   const expected = computeEntryHmac(entry.timestamp, entry.toolName, entry.action, entry.sessionId);
377:   return entry.hmac === expected;
378: }
379: 
380: /** Convert an AuditEntry to SIEM-compatible JSON structure */

Verification: Verification skipped — static-only mode

Fix template: Python: hmac.compare_digest. Node: crypto.timingSafeEqual. Go: subtle.ConstantTimeCompare. Java: MessageDigest.isEqual. C: CRYPTO_memcmp. PHP: hash_equals.


249. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/plugin-manager.ts:388
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

386:         for (const [serverName, config] of Object.entries(manifest.mcpServers)) {
387:           const key = `${manifest.name}__${serverName}`;
388:           configs[key] = config;
389:         }
390:       }
391:     }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


250. 🟠 Object merge / assign from user input without proto guard — CWE-1321

File: src/core/policy/limits.ts:183
Severity: HIGH
Pattern: inj-012-proto-pollution

Why this matters:
Merging a user-provided object into a target without filtering __proto__ or constructor.prototype keys pollutes Object.prototype globally, leading to RCE in subsequent code paths. Jest, Mongoose, Kibana all had this class of CVE.

Code:

181:   /** Update limits at runtime (e.g., from MDM or /policy command) */
182:   updateLimits(partial: Partial<PolicyLimits>): void {
183:     Object.assign(this.limits, partial);
184:   }
185: 
186:   // ── Internal ──

Verification: Verification skipped — static-only mode

Fix template: Use Object.create(null) for the target, or deny-list __proto__/constructor/prototype keys. Prefer immutable merge ({ ...a, ...b } is shallow-safe).


251. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/pro.ts:62
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

60:     const body = payload.slice(0, -len);
61:     const check = payload.slice(-len).toLowerCase();
62:     const expected = createHash("sha256").update(body).digest("hex").slice(0, len);
63:     if (check === expected) return body;
64:   }
65:   return null;

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


252. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/probes/bitcoin-rpc.ts:147
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

145: 
146:     try {
147:       const resp = await fetch(url, {
148:         method: "POST",
149:         headers: {
150:           "Content-Type": "application/json",

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


253. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/prompt-hooks.ts:112
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

110:     const url = `${baseUrl.replace(/\/$/, "")}/v1/chat/completions`;
111: 
112:     const response = await fetch(url, {
113:       method: "POST",
114:       headers: { "Content-Type": "application/json" },
115:       body: JSON.stringify({

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


254. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:111
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

109:             kind = "block";
110: 
111:           boundaries.push({ line: i, name, kind, signature: trimmed.slice(0, 120) });
112:           break;
113:         }
114:       }

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


255. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:173
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

171:           name: defMatch[1]!,
172:           kind: "function",
173:           signature: line.trimEnd().slice(0, 120),
174:         });
175:       } else if (classMatch) {
176:         boundaries.push({

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


256. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:180
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

178:           name: classMatch[1]!,
179:           kind: "class",
180:           signature: line.trimEnd().slice(0, 120),
181:         });
182:       }
183:     }

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


257. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:254
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

252:           name: funcMatch[1]!,
253:           kind: "function",
254:           signature: line.trimEnd().slice(0, 120),
255:         });
256:       } else if (typeMatch) {
257:         boundaries.push({

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


258. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:261
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

259:           name: typeMatch[1]!,
260:           kind: "class",
261:           signature: line.trimEnd().slice(0, 120),
262:         });
263:       }
264:     }

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


259. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:322
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

320:           name: fnMatch[1]!,
321:           kind: "function",
322:           signature: line.trimEnd().slice(0, 120),
323:         });
324:       } else if (structMatch) {
325:         boundaries.push({

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


260. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:329
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

327:           name: structMatch[1]!,
328:           kind: "class",
329:           signature: line.trimEnd().slice(0, 120),
330:         });
331:       } else if (implMatch) {
332:         boundaries.push({

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


261. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:336
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

334:           name: implMatch[1]!,
335:           kind: "class",
336:           signature: line.trimEnd().slice(0, 120),
337:         });
338:       } else if (traitMatch) {
339:         boundaries.push({

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


262. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:343
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

341:           name: traitMatch[1]!,
342:           kind: "class",
343:           signature: line.trimEnd().slice(0, 120),
344:         });
345:       }
346:     }

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


263. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/rag/chunker.ts:513
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

511:   /** Hash content to create a stable chunk ID */
512:   hashContent(input: string): string {
513:     return createHash("sha256").update(input).digest("hex").slice(0, 16);
514:   }
515: 
516:   /** Get path relative to project root */

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


264. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/response-cache.ts:63
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

61:   }
62: 
63:   return hash.digest("hex").slice(0, 32);
64: }
65: 
66: /**

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


265. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918

File: src/core/router.ts:510
Severity: HIGH
Pattern: inj-004-ssrf-fetch

Why this matters:
Server-Side Request Forgery: the server fetches a URL chosen by the attacker. Used to reach internal services (Redis, metadata endpoints like 169.254.169.254 on AWS, admin panels), bypassing network boundaries. Capital One 2019 breach = SSRF.

Code:

508:   try {
509:     const url = `${baseUrl.replace(/\/+$/, "")}/v1/models`;
510:     const res = await fetch(url, { signal: AbortSignal.timeout(ENDPOINT_PROBE_TIMEOUT_MS) });
511:     alive = res.ok;
512:   } catch {
513:     alive = false;

Verification: Verification skipped — static-only mode

Fix template: Add allowlist of permitted hosts. Block RFC1918 + loopback + cloud metadata endpoints. Resolve the hostname first and validate the IP, not just the input string.


266. 🟠 HMAC compared with only a prefix / short substring — CWE-328

File: src/core/session-snapshot.ts:91
Severity: HIGH
Pattern: crypto-015-hmac-truncation

Why this matters:
Truncating an HMAC to a few bytes (say 8 hex chars = 32 bits) lets an attacker brute-force a collision in 2^32 requests — trivially feasible. Some codebases do this to fit into URL/cookie constraints and create a hash collision vulnerability.

Code:

89: 
90: function hashString(str: string): string {
91:   return createHash("sha256").update(str).digest("hex").slice(0, 16);
92: }
93: 
94: function generateId(): string {

Verification: Verification skipped — static-only mode

Fix template: Keep HMAC outputs at full length (32 bytes for HMAC-SHA256). If space is truly limited, use a longer underlying hash and truncate to ≥16 bytes.


267. 🟠 File operation following symlinks without resolution check (TOCTOU) — CWE-59

File: src/core/setup-wizard.ts:54
Severity: HIGH
Pattern: uni-015-symlink-toctou

Why this matters:
Check-then-use patterns on files are vulnerable to TOCTOU attacks via symlinks. Between the check (exists/stat/access) and the use (open/read/write), an attacker can replace the file with a symlink pointing to a sensitive location.

Code:

52:     // eslint-disable-next-line @typescript-eslint/no-require-imports
53:     const fs = require("node:fs") as typeof import("node:fs");
54:     if (!fs.existsSync(path)) return undefined;
55:     const raw = JSON.parse(fs.readFileSync(path, "utf-8")) as Record<string, unknown>;
56:     const val = raw[field];
57:     return typeof val === "string" && val.length > 0 ? val : undefined;

Verification: Verification skipped — static-only mode

Fix template: Use atomic operations (openat with O_NOFOLLOW, fstat on the open fd, realpath + prefix check).


268. 🟠 Prototype pollution via bracket notation with user key — CWE-1321

File: src/core/skills.ts:314
Severity: HIGH
Pattern: js-008-prototype-pollution-bracket

Why this matters:
Setting object properties via bracket notation with a user-controlled key allows prototype pollution. An attacker can set proto.isAdmin = true to affect all objects.

Code:

312:           const key = part.slice(0, eqIdx);
313:           const value = part.slice(eqIdx + 1);
314:           templateArgs[key] = value;
315:         } else {
316:           freeArgs.push(part);
317:         }

Verification: Verification skipped — static-only mode

Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects.


269. 🟡 Promise chain without .catch() (unhandled rejection) — CWE-755

File: src/core/config.ts:809
Severity: MEDIUM
Pattern: js-015-promise-no-catch

Why this matters:
A Promise .then() chain without .catch() leads to unhandled promise rejections. In Node.js, unhandled rejections crash the process by default.

Code:

807:     }
808:   };
809:   _settingsSaveLock = _settingsSaveLock.then(op, op);
810:   return _settingsSaveLock;
811: }
812: 

Verification: Verification skipped — static-only mode

Fix template: Add .catch(err => { /* handle */ }) at the end of the chain, or use async/await with try/catch.


270. 🟡 Promise chain without .catch() (unhandled rejection) — CWE-755

File: src/core/config.ts:838
Severity: MEDIUM
Pattern: js-015-promise-no-catch

Why this matters:
A Promise .then() chain without .catch() leads to unhandled promise rejections. In Node.js, unhandled rejections crash the process by default.

Code:

836:     }
837:   };
838:   _settingsSaveLock = _settingsSaveLock.then(op, op);
839:   return _settingsSaveLock;
840: }
841: 

Verification: Verification skipped — static-only mode

Fix template: Add .catch(err => { /* handle */ }) at the end of the chain, or use async/await with try/catch.


271. 🟡 JSON.parse without try/catch (crash on invalid input) — CWE-754

File: src/core/distillation/curator.ts:114
Severity: MEDIUM
Pattern: js-014-json-parse-no-catch

Why this matters:
JSON.parse() throws SyntaxError on invalid JSON. Without try/catch, malformed input crashes the process or rejects the promise unhandled.

Code:

112: 
113:     // Try JSON array
114:     const parsed = JSON.parse(text);
115:     if (Array.isArray(parsed)) {
116:       return parsed.map((entry: Record<string, unknown>) => this.normalizeEntry(entry));
117:     }

Verification: Verification skipped — static-only mode

Fix template: Wrap in try/catch: try { const obj = JSON.parse(data); } catch (e) { /* handle */ }


272. 🟡 JSON.parse without try/catch (crash on invalid input) — CWE-754

File: src/core/permissions/per-tool-policy.ts:172
Severity: MEDIUM
Pattern: js-014-json-parse-no-catch

Why this matters:
JSON.parse() throws SyntaxError on invalid JSON. Without try/catch, malformed input crashes the process or rejects the promise unhandled.

Code:

170: 
171:     const text = require("node:fs").readFileSync(settingsPath, "utf-8");
172:     const settings = JSON.parse(text);
173: 
174:     if (!settings.toolPolicies || !Array.isArray(settings.toolPolicies)) {
175:       return [];

Verification: Verification skipped — static-only mode

Fix template: Wrap in try/catch: try { const obj = JSON.parse(data); } catch (e) { /* handle */ }


273. 🟡 JSON.parse without try/catch (crash on invalid input) — CWE-754

File: src/core/session-branch.ts:117
Severity: MEDIUM
Pattern: js-014-json-parse-no-catch

Why this matters:
JSON.parse() throws SyntaxError on invalid JSON. Without try/catch, malformed input crashes the process or rejects the promise unhandled.

Code:

115:       if (existsSync(filePath)) {
116:         const content = readFileSync(filePath, "utf-8");
117:         return JSON.parse(content) as SessionBranch;
118:       }
119:     }
120:   } catch {

Verification: Verification skipped — static-only mode

Fix template: Wrap in try/catch: try { const obj = JSON.parse(data); } catch (e) { /* handle */ }


274. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697

File: src/core/audit-engine/taint/java.ts:489
Severity: LOW
Pattern: js-013-loose-equality

Why this matters:
The == operator performs type coercion, leading to surprising results: '' == false, 0 == '', null == undefined. This causes subtle bugs in conditionals.

Code:

487:       if (bound) return { ...bound, reason: `param '${trimmed}' bound: ${bound.reason}` };
488:     }
489:     if (!ctx.fileContent || ctx.currentLine == null) {
490:       return { origin: "unknown", reason: `identifier '${trimmed}' (no file ctx)` };
491:     }
492:     const visited = ctx.visited ?? new Set<string>();

Verification: Verification skipped — static-only mode

Fix template: Use === for strict equality, or == null specifically for null/undefined checks.


275. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697

File: src/core/balance/index.ts:166
Severity: LOW
Pattern: js-013-loose-equality

Why this matters:
The == operator performs type coercion, leading to surprising results: '' == false, 0 == '', null == undefined. This causes subtle bugs in conditionals.

Code:

164: function computeAlert(state: BalanceState, provider: BillingProvider): ThresholdAlert | null {
165:   const entry = state.providers[provider];
166:   if (!entry || entry.starting == null || entry.starting <= 0) return null;
167:   const remaining = Math.max(0, entry.starting - entry.spent);
168:   const fraction = remaining / entry.starting;
169:   const lastFired = state.lastAlertedPct[provider] ?? Infinity;

Verification: Verification skipped — static-only mode

Fix template: Use === for strict equality, or == null specifically for null/undefined checks.


276. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697

File: src/core/debug-engine/debug-patterns.ts:229
Severity: LOW
Pattern: js-013-loose-equality

Why this matters:
The == operator performs type coercion, leading to surprising results: '' == false, 0 == '', null == undefined. This causes subtle bugs in conditionals.

Code:

227:       codeSignals: [
228:         {
229:           pattern: /==(?!=)/,
230:           meaning: "Loose equality (==) — type coercion bug",
231:           likely_fix: "Use strict equality (===)",
232:         },

Verification: Verification skipped — static-only mode

Fix template: Use === for strict equality, or == null specifically for null/undefined checks.


277. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697

File: src/core/request-builder.ts:783
Severity: LOW
Pattern: js-013-loose-equality

Why this matters:
The == operator performs type coercion, leading to surprising results: '' == false, 0 == '', null == undefined. This causes subtle bugs in conditionals.

Code:

781:           });
782:         }
783:         return m.content == null;
784:       })();
785:       if (isEmpty) {
786:         const shape =

Verification: Verification skipped — static-only mode

Fix template: Use === for strict equality, or == null specifically for null/undefined checks.


278. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697

File: src/core/semantic-guards.ts:55
Severity: LOW
Pattern: js-013-loose-equality

Why this matters:
The == operator performs type coercion, leading to surprising results: '' == false, 0 == '', null == undefined. This causes subtle bugs in conditionals.

Code:

53:   // inversion. Look for `(str|wcs|...)cmp\([^)]*\)\s*==\s*0` pattern in old.
54:   const cmpEqZeroRegex =
55:     /\b(?:str|wcs|strn|wcsn|mem|strcase|strncase|strcoll|wcscoll)cmp\s*\([^)]*\)\s*==\s*0/g;
56:   const oldEqZeroCount = (oldStr.match(cmpEqZeroRegex) || []).length;
57: 
58:   if (oldEqZeroCount >= added) {

Verification: Verification skipped — static-only mode

Fix template: Use === for strict equality, or == null specifically for null/undefined checks.


Pattern hit-rate

23 patterns fired during this run. Top entries by hit count:

Pattern Hits Sites Confirmed FP needs_context confirmed_rate
js-007-command-injection 68 68 68 0 0 100%
inj-004-ssrf-fetch 35 35 35 0 0 100%
js-008-prototype-pollution-bracket 33 33 33 0 0 100%
js-ast-002-child-process-exec-of-parameter 30 30 30 0 0 100%
js-ast-001-eval-of-parameter 27 27 27 0 0 100%
crypto-015-hmac-truncation 26 26 26 0 0 100%
uni-003-ssrf 12 12 12 0 0 100%
js-ast-005-eval-of-tainted-expression 8 8 8 0 0 100%
js-ast-006-exec-of-tainted-expression 6 6 6 0 0 100%
inj-012-proto-pollution 5 5 5 0 0 100%

…and 13 more patterns. See AUDIT_REPORT.json → pattern_metrics for the full list.

Methodology

This audit was produced by the KCode audit engine: a deterministic pattern library scanned the project for known-dangerous code patterns, then every candidate was verified against the actual execution path. Findings listed here are only those where the execution path was confirmed.

Pattern library version: 1.0 — patterns derived from real bugs found in production C/C++ codebases (network I/O, USB/HID decoders, resource lifecycle, integer arithmetic).


Generated by KCode — Astrolexis.space


Astrolexis.space — Kulvex Code

@GaltRanch GaltRanch merged commit 85181c5 into master May 26, 2026
4 of 6 checks passed
@GaltRanch GaltRanch deleted the feat/inquisitor-bridge branch May 26, 2026 20:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant