feat(inquisitor): bridge KCode to Inquisitor for CVE-grade evidence#112
Conversation
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>
🔍 KCode Security AuditAudit Report — KCodeAuditor: Astrolexis.space — Kulvex Code Audit ConfidenceScore: 25 / 100
Coverage: 500 / 1305 files (38%) — full scan ⚠ Warnings:
Coverage
Summary
Severity breakdown
Full reportAudit Report — KCodeAuditor: Astrolexis.space — Kulvex Code Audit ConfidenceScore: 25 / 100
Coverage: 500 / 1305 files (38%) — full scan ⚠ Warnings:
Coverage
Summary
Severity breakdown
Findings1. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: 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-95File: Why this matters: 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-78File: Why this matters: 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-77File: Why this matters: 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-95File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(fileContent) // arg is a parameter of the enclosing functionVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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_logVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: 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-95File: Why this matters: 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-95File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: Code: .exec(assistantText) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(text) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: Code: .exec(text) // arg is a parameter of the enclosing functionVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: 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-78File: Why this matters: Code: .exec(command) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .spawn(cmd) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .spawn(cmd) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 persistenceVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 managementVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 searchVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 storageVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-89File: Why this matters: 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: 98. 🔴 child_process.exec / spawn / execFile of a function parameter (command injection via AST) — CWE-78File: Why this matters: Code: .spawn(cmd) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .spawn(cmd) // arg is a parameter of the enclosing functionVerification: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: Code: .exec(text) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: 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-95File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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 BEGINVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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 maxVerification: 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-78File: Why this matters: 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 buildVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(content) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: Code: setTimeout(resolve) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-78File: Why this matters: Code: .exec(line) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: Code: .exec(line) // arg is a parameter of the enclosing functionVerification: 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-78File: Why this matters: 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-78File: Why this matters: 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-95File: Why this matters: 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-95File: Why this matters: Code: setTimeout(r) // arg is a parameter — setTimeout/setInterval with a non-function first arg evaluates as codeVerification: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: Code: 96: }
97: if (extra) {
98: Object.assign(h, extra);
99: }
100: return h;
101: }Verification: Verification skipped — static-only mode Fix template: Use 154. 🟠 User input flows into HTTP request URL (SSRF) — CWE-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: Code: 112: parameters: missing,
113: });
114: Object.assign(params, interactive);
115: }
116:
117: // Dry runVerification: Verification skipped — static-only mode Fix template: Use 168. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918File: Why this matters: 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-328File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-328File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: 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: 176. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918File: Why this matters: 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-918File: Why this matters: 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-384File: Why this matters: 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-1321File: Why this matters: 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 configVerification: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-287File: Why this matters: 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-208File: Why this matters: 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-287File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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 parsingVerification: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-287File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: 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 206. 🟠 HMAC compared with only a prefix / short substring — CWE-328File: Why this matters: 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-328File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-328File: Why this matters: 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-1333File: Why this matters: Code: RegExp(pattern) // arg is a parameter — caller-controlled regex source is a ReDoS sinkVerification: 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-1321File: Why this matters: 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-59File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-287File: Why this matters: 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-208File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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-328File: Why this matters: 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-1321File: Why this matters: 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 238. 🟠 HTTP fetch / urlopen of user-provided URL without allowlist — CWE-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-208File: Why this matters: 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-1321File: Why this matters: 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-1321File: Why this matters: 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 251. 🟠 HMAC compared with only a prefix / short substring — CWE-328File: Why this matters: 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-918File: Why this matters: 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-918File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-328File: Why this matters: 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-918File: Why this matters: 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-328File: Why this matters: 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-59File: Why this matters: 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-1321File: Why this matters: 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-755File: Why this matters: 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-755File: Why this matters: 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-754File: Why this matters: 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-754File: Why this matters: 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-754File: Why this matters: 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-697File: Why this matters: 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-697File: Why this matters: 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-697File: Why this matters: 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-697File: Why this matters: 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-697File: Why this matters: 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-rate23 patterns fired during this run. Top entries by hit count:
…and 13 more patterns. See MethodologyThis 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 |
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:
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
src/integrations/inquisitor.ts(new)~/.inquisitor/token(orINQUISITOR_TOKENenv), POSTs toINQUISITOR_URL(defaulthttps://api.astrolexis.space/inquisitor/v1), translates HTTP responses into typedInquisitorErrors with actionable hints.src/cli/commands/reproduce.ts(new)kcode reproduce <finding-id>— pulls a confirmed finding fromAUDIT_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-runfor validation without submission.src/cli/commands/index.tssrc/index.tsREADME.mdUX 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:
Other failure modes covered (with hints):
disclose)Configuration
INQUISITOR_URLhttps://api.astrolexis.space/inquisitor/v1INQUISITOR_TOKEN_FILE~/.inquisitor/tokenINQUISITOR_TOKENSelf-hosted Enterprise tier just points
INQUISITOR_URLat their own daemon. KCode is endpoint-agnostic.Test plan
bun run typecheck— clean (no new errors).bun run lint— clean afterlint:fix.kcode --help— four new commands appear in the subcommand list.kcode validate /bin/lswith no token + unreachable URL — prints the upsell message and exits 1.Rollout
Backwards-compatible. Existing
kcode audit,kcode --print, and every other command behave identically. The four new commands appear in--helpbut only do anything for users who set up Inquisitor.When Inquisitor's
astrolexis-apiexposes 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