audit: overhaul /fix honesty, per-ecosystem filters, scanner safety (v2.10.6 → v2.10.13) - #2
Conversation
…rminal title polish Audit engine scanner was walking into Flutter ephemeral/plugin-symlink trees and iOS/Android generated build output, reporting findings in vendored plugin code the user did not write. Scanning SmartSolar/ produced 17 "confirmed" findings where every top hit was under mobile/windows/flutter/ephemeral/.plugin_symlinks/ — all third-party plugin code. Added to SKIP_DIRS: .dart_tool, .plugin_symlinks, ephemeral, .flutter-plugins, .flutter-plugins-dependencies, Pods, DerivedData, xcuserdata, .gradle, .idea, .cxx, .kotlin, .mvn Also: - sh-001-eval-injection was registered under c/cpp/python/js/ts/go/ rust/java; it's a shell-only pattern. Moved to languages: ["shell"] and added "shell" to the Language union in types.ts. - Terminal tab title cleaned up: fast emoji frames replaced with a professional filling-block spinner (▰▱▱▱ → ▰▰▰▰ → ▱▱▱▱), idle state shows "▪ KCode" instead of "✅ KCode". - Bump to v2.10.7. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extends the scanner false-positive filter from Flutter/iOS/Android to
every ecosystem the audit engine understands. The scanner now applies
three layered filters instead of just directory-name matching:
1. SKIP_DIRS — expanded to cover:
- JS/TS: .next .nuxt .svelte-kit .turbo .parcel-cache .vuepress
.docusaurus .cache coverage .nyc_output
- Python: .pytest_cache .mypy_cache .ruff_cache .tox site-packages env
- Ruby: .bundle
- Elixir: _build deps .elixir_ls
- Scala: .bloop .metals
- Haskell: .stack-work dist-newstyle
- C/C++: CMakeFiles .ccls-cache cmake-build-{debug,release,relwithdebinfo}
- Swift: .build .swiftpm (SPM build output)
- .NET: bin obj packages .vs
- Universal VCS/IDE: .hg .svn .vscode
- Vendored: Godeps
2. SKIP_PATH_SUBSTRINGS (new) — matches anywhere in the relative path,
not just as a literal top-level directory name:
/generated/ /.generated/ /_generated/
/build/intermediates/ /build/generated/
/autogen/ /auto-generated/
3. SKIP_FILENAME_PATTERNS (new) — regex over basenames to catch
generated files that language toolchains emit inside user-authored
trees:
- JS minified/bundled: *.min.{js,mjs,css} *.bundle.js *.chunk.js *.map
- Dart code-gen: *.g.dart *.freezed.dart *.gr.dart *.config.dart
- Python protobuf/grpc: *_pb.py *_pb2.py *_pb2_grpc.py
- Go protobuf/mocks/stringer: *.pb.go *.pb.gw.go *_mock.go *_string.go
- C/C++ Qt moc / flex / bison / protobuf:
moc_*.{cc,cpp} ui_*.h *.pb.{cc,cpp,h} lex.*.c *.tab.{c,h}
- C# WinForms/XAML designer: *.designer.cs *.g.cs *.g.i.cs
- Swift generated: Generated*.swift
- Java DI codegen: *_Factory.java *_MembersInjector.java Dagger*.java
4. Minified-file heuristic — scanProject() now skips any file whose
longest line exceeds 5,000 chars. Catches minified JS/CSS with
non-standard names that slip past filename filters. Threshold is
conservative enough to spare generated SQL schemas and long strings.
Verified against /home/curly/proyectos/SmartSolar: scan sees 414 real
source files, with 0 files remaining under .plugin_symlinks/, ephemeral/,
.dart_tool/, Pods/, DerivedData/, or build/intermediates/. The SmartSolar
run that reported 17 confirmed findings (all in vendored Flutter plugin
code) should now report only genuine user-code findings.
Bump to v2.10.8. All 25 audit-engine tests still pass.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SmartSolar audit reported two low-severity findings on circuit-breaker modules (dess_client.py, kulvex_client.py) that use module-level _circuit_open_until for the breaker state. That is a textbook idiomatic Python circuit-breaker — httpx, tenacity, and most production clients ship the same shape. Flagging it as a code smell produces noise and trains users to ignore the report. Expanded the verify_prompt so the LLM verifier explicitly recognizes nine well-known module-level-state patterns as FALSE_POSITIVE: 1. module-level logger 2. configuration / settings cache 3. singleton lazy-init (_instance, _client, _pool) 4. circuit breaker state 5. rate limiter / token bucket 6. connection pool / HTTP session reuse 7. feature flag cache / hot-reloaded config 8. memoization / LRU cache 9. test fixtures / monkeypatch Only globals that pass arbitrary state between unrelated functions — the "should have been a class" smell — are still reported as CONFIRMED. Bump to v2.10.9. All 25 audit-engine tests still pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Root cause. /fix had two tiers of recipes:
- Bespoke fixers (11 patterns) that rewrite real code.
- Generic PATTERN_RECIPES (~230 patterns) that insert a KCODE-AUDIT
advisory comment above the buggy line, LEAVING THE BUG IN PLACE.
The old result type only had `applied: boolean`, so both branches
returned `applied: true`. The UI printed "✅ Applied: N fixes" and
users understandably assumed the code was fixed. It wasn't — the bug
was still there with a TODO sticker on top.
This was caught dogfooding /fix on the SmartSolar Flutter project: 5
"fixes" were all KCODE-AUDIT comments, zero actual code changes.
Fix. Add FixKind = "transformed" | "annotated" | "skipped" to
FixResult and OneFixResult:
- transformed: bespoke fixer rewrote real code
- annotated: generic recipe inserted a KCODE-AUDIT comment;
buggy code UNCHANGED, finding still needs manual work
- skipped: no fix was applied
applied: boolean is kept for existing callers and is true for both
transformed and annotated (since both modify the file somehow).
The /fix UI in file-actions.ts now reports three buckets separately
so users see the honest count: "✅ Fixed: 4 (real code transforms) /
📝 Annotated: 1 (advisory comment only — still needs manual fix)".
workflow-chain.ts counts only transformed as fixes_applied so the
orchestrator doesn't over-claim completion.
Real Dart fixers added:
dart-007-json-null-check: rewrites `as int` → `as int? ?? 0`,
`as String` → `as String? ?? ''`, `as double` → `as double? ?? 0.0`,
`as num` → `as num? ?? 0`, `as bool` → `as bool? ?? false` inside
fromJson-style factories. Sweeps the whole file because the audit
engine collapses repeated matches into a single finding. Idempotent
— lines already using `as T? ?? default` are left alone.
dart-005-setstate-after-dispose: inserts `if (!mounted) return;`
before any setState() that follows an await, skipping if a
mounted/disposed guard is already present in the preceding 3
non-blank lines.
Both are registered in BESPOKE_PATTERN_IDS and covered by new tests.
Verified end-to-end against SmartSolar's AUDIT_REPORT.json: the 4
Dart model files get real code rewrites (14 casts transformed across
plant/device/alert/automation), and the one websocket_service.dart
finding is honestly reported as "📝 annotated" because dart-006 still
uses a generic recipe. No more lying to the user.
All 28 audit-engine tests pass (8 new fixer tests). Bump to v2.10.10.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Self-review of the previous /fix overhaul surfaced six issues. Three were high-severity correctness bugs that could silently corrupt user code; three were medium-severity correctness/robustness bugs. All six are closed here with targeted tests. HIGH #1 — fixDartJsonNullCheck over-matched The regex `/\\bas\\s+(int|double|num|bool|String)\\b(?!\\?)/g` had no context requirement, so it rewrote any primitive cast on any line: final count = users.length as int; // ← was getting rewritten final x = someCall() as String; // ← was getting rewritten Business-logic casts that had nothing to do with JSON were silently turned into `as int? ?? 0` / `as String? ?? ''`, changing runtime behavior (exception → default value). The fix tightens the regex to require a `json['key']` subscript immediately preceding the `as`: /(\\bjson\\s*\\[\\s*['"][^'"]+['"]\\s*\\]\\s*as\\s+(int|...))\\b(?!\\?)/g Only casts that live inside the exact `json[...] as T` shape are rewritten now. A regression test (mixed.dart) exercises a file with both kinds of casts and asserts the non-json ones are untouched. HIGH #2 — whole-file sweep amplified false positives The dart-007 fixer sweeps the entire file (needed because the audit engine dedupes repeated matches of the same pattern+file into a single Finding, so only the first line is reported). Combined with HIGH #1, a single false-positive finding could rewrite every cast in the file. Narrowing the regex in #1 largely addresses this — the sweep now only touches lines that contain the literal `json['...']` subscript, so the blast radius is bounded to fromJson factories. HIGH #3 — writeFileSync was not atomic if (modified) { writeFileSync(file, lines.join("\\n")); } A crash mid-write (Ctrl-C, OOM, disk full, process kill) left the user's source file half-corrupted with no recovery. Introduced `atomicWriteFileSync()`: write to `<target>.kcode-fix-<rand>.tmp` then `renameSync` over the target. The rename is atomic on POSIX since the temp file is in the same directory. On rename failure the temp file is cleaned up and the error propagates. MEDIUM #4 — setState guard detection short-window fixDartSetStateAfterDispose only looked at the 3 non-blank lines immediately before `setState(` for a mounted/disposed guard. A valid guard placed just after the `await` but separated from the setState by comments or blank lines was missed, causing a duplicate guard to be inserted. Replaced the short lookback with a full-span walk from the await line (finding.line) to the setState call. Regression test state.dart exercises a 6-line gap and asserts exactly one guard. MEDIUM #5 — dart-005 assumed `mounted` always exists The fixer inserted `if (!mounted) return;` without verifying the enclosing class is a State<T> subclass. In rare cases (helper classes, mixins, non-Flutter Dart with a local `setState` method) `mounted` is undefined and the inserted guard fails to compile. Added `isInsideFlutterState()` which walks backward looking for a `class X extends ... State<...>` declaration; if not found within 400 lines, the fix is skipped with an explanatory message. Regression test helper.dart has a non-State class named `NotAState` and asserts no guard is inserted. MEDIUM #6 — scanner could escape the project root and loop on cyclic symlinks findSourceFiles used readdirSync + statSync, which follows symlinks silently. A link pointing outside the audited project leaked files from unrelated directories into the scan; a cyclic link (a→b→a or link→.) would walk forever until file-descriptor exhaustion. Scanner now: - Resolves the project root to a realpath once at start. - Resolves every directory AND file via realpath before visiting. - Rejects resolved paths that don't equal or start with `<projectRealpath>/` — closes the root-escape hole. - Tracks visited directories and files in two Sets keyed by real path — closes the cycle-loop hole. Two regression tests in audit-engine.test.ts create sibling directories with escaping and cyclic symlinks and assert the scanner neither leaks outside files nor loops. Both tests degrade gracefully on platforms where symlink creation requires privileges. Bump to v2.10.11. Audit-engine suite now has 33 passing tests (was 28) covering all six holes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Reviewing audit outputs across projects surfaced a real correctness
bug: websocket_service.dart in SmartSolar had TWO identical
`KCODE-AUDIT:dart-006-future-no-error` annotation lines stacked one
on top of the other. Root cause:
const prev = lines[idx - 1] ?? "";
if (prev.includes(tag)) { return /* skipped */; }
The guard only inspected the single line immediately above the
insertion point. When /fix is re-run with a stale AUDIT_REPORT.json
(which holds the line numbers from BEFORE the first annotation was
inserted), the line targeted by the second run has drifted by one,
and the previously-inserted annotation now sits at `idx - 2`, not
`idx - 1`. The guard misses it and inserts a duplicate.
Fix: scan a ±3-line window around the insertion point for the tag.
Three positions is enough to absorb repeated /fix runs on stale
reports without costing noticeable CPU (worst case 7 string checks
per finding).
Regression test: run /fix three times against the same source file
(first against a fresh audit, then again with the stale audit,
then again with a fresh re-scan that has shifted line numbers) and
assert the annotation count stays at exactly 1 across all three.
Bump to v2.10.12. 34 passing audit-engine tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
KCode's audit engine flagged two real bugs in its own source tree
and the previous /fix run only added advisory KCODE-AUDIT comments.
These are the actual code fixes:
1. HIGH — prototype pollution in McpManager.loadFromConfigs
(src/core/mcp.ts:167, js-008-prototype-pollution-bracket)
A malicious --mcp-config JSON could use `__proto__`, `constructor`,
or `prototype` as a server name; the previous code did
validated[name] = config as McpServerConfig;
into a plain object literal, which poisons Object.prototype for
the rest of the process. The fix rejects those three keys
explicitly and uses `Object.create(null)` for the accumulator so
even a bypass cannot reach a real prototype chain.
Regression test: src/core/mcp-proto-pollution.test.ts feeds the
manager a hostile config with all three reserved keys and asserts
Object.prototype stays clean; also asserts a legitimate server
name still round-trips through startServers.
2. MEDIUM — unguarded JSON.parse in parseNotebook
(src/tools/notebook-utils.ts:36, js-014-json-parse-no-catch)
A corrupt .ipynb would bubble a raw SyntaxError up to whatever
callsite touched it, with no indication that the failure was a
notebook parse. parseNotebook now wraps JSON.parse in try/catch
and re-raises as "Invalid notebook JSON: <message>", and adds a
defensive check that the parsed root is an object (so a bare
string literal or a number doesn't get cast to JupyterNotebook
and blow up later with a cryptic "cells is undefined").
Regression tests verify the "Invalid notebook JSON" message and
the "root is not an object" guard.
The leftover KCODE-AUDIT advisory comments at those two locations
are removed, since the bugs they pointed at no longer exist.
Bump to v2.10.13. Audit-engine suite unchanged at 34 passing; MCP
sanitization + notebook tests now at 45 passing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
🔍 KCode Security AuditAudit Report — KCodeAuditor: Astrolexis.space — Kulvex Code Summary
Severity breakdown
Full reportAudit Report — KCodeAuditor: Astrolexis.space — Kulvex Code 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. 🔴 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. 3. 🔴 eval() with potentially untrusted input — CWE-95File: Why this matters: Code: 519:
520: /**
521: * py-001: Replace eval() with ast.literal_eval().
522: */
523: function fixPyEval(lines: string[], finding: Finding): OneFixResult {
524: const idx = finding.line - 1;Verification: Verification skipped — static-only mode (+3 more matches of this pattern in the same file) Fix template: Remove eval() or use JSON.parse() for data, Function constructor for controlled cases. 4. 🔴 eval() with potentially untrusted input — CWE-95File: Why this matters: Code: 259: {
260: id: "py-001-eval-exec",
261: title: "eval()/exec() with potentially untrusted input",
262: severity: "critical",
263: languages: ["python"],
264: regex: /\b(eval|exec)\s*\(/g,Verification: Verification skipped — static-only mode (+16 more matches of this pattern in the same file) Fix template: Remove eval() or use JSON.parse() for data, Function constructor for controlled cases. 5. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 35:
36: function git(cwd: string, args: string): string {
37: return execSync(`git ${args}`, { cwd, encoding: "utf-8", timeout: 30_000, stdio: ["pipe", "pipe", "pipe"] }).trim();
38: }
39:
40: function gh(cwd: string, args: string): string {Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 6. 🔴 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 (+3 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 7. 🔴 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 (+2 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 8. 🔴 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 (+1 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 9. 🔴 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 (+1 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 10. 🔴 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 (+34 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 11. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 100: for (const smiPath of NVIDIA_SMI_PATHS) {
101: try {
102: const output = execSync(`${smiPath} ${NVIDIA_QUERY} ${NVIDIA_FORMAT}`, {
103: encoding: "utf-8",
104: timeout: 10_000,
105: stdio: ["pipe", "pipe", "pipe"],Verification: Verification skipped — static-only mode Fix template: Use spawn/execFile with array args instead of shell string. 12. 🔴 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. 13. 🔴 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. 14. 🔴 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 (+7 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 15. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 365: for (const cmd of prerequisites) {
366: try {
367: execSync(`which ${cmd}`, { stdio: "pipe", timeout: 5000 });
368: } catch {
369: log.error("setup", `Build prerequisite missing: ${cmd}`);
370: progress(`Cannot build from source: '${cmd}' not found. Install it and retry.\n`);Verification: Verification skipped — static-only mode (+4 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 16. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 9: // Isolated in-memory DB for tests
10: const testDb = new Database(":memory:");
11: testDb.exec(`CREATE TABLE IF NOT EXISTS narrative (
12: id INTEGER PRIMARY KEY AUTOINCREMENT,
13: summary TEXT NOT NULL,
14: project TEXT NOT NULL DEFAULT '',Verification: Verification skipped — static-only mode Fix template: Use spawn/execFile with array args instead of shell string. 17. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 43: ).run(summary, data.project, data.toolsUsed.join(", "), data.actionsCount);
44: // Prune: keep last 50 or last 30 days
45: db.exec(
46: `DELETE FROM narrative WHERE id NOT IN (SELECT id FROM narrative ORDER BY created_at DESC LIMIT 50) OR created_at < datetime('now', '-30 days')`,
47: );
48: log.info("narrative", `Session narrative saved: ${summary.slice(0, 80)}...`);Verification: Verification skipped — static-only mode Fix template: Use spawn/execFile with array args instead of shell string. 18. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 139: const { execSync } = require("node:child_process");
140: if (process.platform === "linux") {
141: execSync(`notify-send "${safeTitle}" "${safeBody}" 2>/dev/null`, { timeout: 3000 });
142: } else if (process.platform === "darwin") {
143: execSync(
144: `osascript -e 'display notification "${safeBody}" with title "${safeTitle}"' 2>/dev/null`,Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 19. 🔴 eval() with potentially untrusted input — CWE-95File: Why this matters: Code: 356: - Insufficient logging & monitoring
357: 3. Check for language-specific issues:
358: - TypeScript/JS: eval(), innerHTML, dangerouslySetInnerHTML, prototype pollution
359: - Python: pickle, exec, shell=True, format string injection
360: - Go: sql.Query with string concat, unsafe pointer use
361: 4. Report findings with severity (CRITICAL/HIGH/MEDIUM/LOW), file:line, and fix recommendation.Verification: Verification skipped — static-only mode Fix template: Remove eval() or use JSON.parse() for data, Function constructor for controlled cases. 20. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 445: export function getDiskUsage(cwd: string): string | null {
446: try {
447: const output = execSync(
448: `df -h "${cwd}" 2>/dev/null | tail -1 | awk '{print $4 " available (" $5 " used)"}'`,
449: {
450: stdio: "pipe",Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 21. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 8: function createTestDb(): Database {
9: const db = new Database(":memory:");
10: db.exec(`CREATE TABLE IF NOT EXISTS user_model (
11: key TEXT PRIMARY KEY, value REAL NOT NULL, samples INTEGER NOT NULL DEFAULT 1,
12: updated_at TEXT NOT NULL DEFAULT (datetime('now'))
13: )`);Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 22. 🔴 Shell command with template literal (injection) — CWE-78File: Why this matters: Code: 75: // Try arecord first (ALSA), then sox
76: try {
77: execSync(
78: `arecord -f S16_LE -r ${SAMPLE_RATE} -c 1 -d ${durationSec} "${outPath}" 2>/dev/null`,
79: { stdio: "pipe", timeout: (durationSec + 2) * 1000 },
80: );Verification: Verification skipped — static-only mode (+4 more matches of this pattern in the same file) 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: 1172: };
1173: try {
1174: const raw = execSync(`gh pr view ${prNumber} --json title,body,files,comments`, {
1175: encoding: "utf-8",
1176: timeout: 15_000,
1177: }).trim();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: 20:
21: private ensureTable(): void {
22: this.db.exec(`
23: CREATE TABLE IF NOT EXISTS telemetry_events (
24: id INTEGER PRIMARY KEY AUTOINCREMENT,
25: name TEXT NOT NULL,Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use spawn/execFile with array args instead of shell string. 25. 🟠 dangerouslySetInnerHTML with dynamic content — CWE-79File: Why this matters: Code: 928: \`\`\`tsx
929: function UserComment({ comment }: { comment: string }) {
930: return <div dangerouslySetInnerHTML={{ __html: comment }} />;
931: }
932: \`\`\`
933: Verification: Verification skipped — static-only mode Fix template: Use DOMPurify: { __html: DOMPurify.sanitize(content) } 26. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 320: div.className = 'message ' + role;
321: if (id) div.dataset.id = id;
322: div.innerHTML = '<div class="role">' + (role === 'user' ? 'You' : 'KCode') + '</div>' +
323: '<div class="content">' + escapeHtml(content) + '</div>';
324: messagesEl.appendChild(div);
325: messagesEl.scrollTop = messagesEl.scrollHeight;Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 27. 🟠 innerHTML assignment with dynamic content (XSS) — CWE-79File: Why this matters: Code: 320: div.className = 'message ' + role;
321: if (id) div.dataset.id = id;
322: div.innerHTML = '<div class="role">' + (role === 'user' ? 'You' : 'KCode') + '</div>' +
323: '<div class="content">' + escapeHtml(content) + '</div>';
324: messagesEl.appendChild(div);
325: messagesEl.scrollTop = messagesEl.scrollHeight;Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use textContent for text, or sanitize: el.innerHTML = DOMPurify.sanitize(html). 28. 🟠 UserDefaults for sensitive data (should use Keychain) — CWE-312File: Why this matters: Code: 7: class AppSettings: ObservableObject {
8: @Published var serverURL: String {
9: didSet { UserDefaults.standard.set(serverURL, forKey: "serverURL") }
10: }
11:
12: @Published var model: String {Verification: Verification skipped — static-only mode (+7 more matches of this pattern in the same file) Fix template: Use KeychainAccess library or Security framework: SecItemAdd/SecItemCopyMatching. 29. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 2:
3: const STORAGE_SERVER_URL = "kcode_server_url";
4: const STORAGE_API_KEY = "kcode_api_key";
5:
6: const DEFAULT_SERVER_URL = "http://localhost:10091";
7: Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 30. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 87: if (args.length > 0) entry.args = args;
88:
89: data.mcpServers[name] = entry;
90:
91: // Ensure directory exists
92: 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. 31. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 39: test("returns env var if set", () => {
40: const original = process.env.KCODE_AUTH_TOKEN;
41: process.env.KCODE_AUTH_TOKEN = "test-token-123";
42: try {
43: expect(getAuthToken()).toBe("test-token-123");
44: } finally {Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 32. 🟠 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 (+1 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 33. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 710: "If any user data is concatenated or interpolated, respond CONFIRMED.",
711: cwe: "CWE-79",
712: fix_template: "Use textContent for text, or sanitize: el.innerHTML = DOMPurify.sanitize(html).",
713: },
714: {
715: id: "js-011-eval-new-function",Verification: Verification skipped — static-only mode Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 34. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 3103: "If the index could be nil (from function return, optional parameter), respond CONFIRMED.",
3104: cwe: "CWE-476",
3105: fix_template: "Add nil guard: if key ~= nil then tbl[key] = value end",
3106: },
3107: {
3108: id: "lua-004-string-concat-loop",Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 35. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 142: for (const [key, value] of Object.entries(process.env)) {
143: if (value !== undefined && AGENT_ENV_ALLOWLIST.has(key)) {
144: env[key] = value;
145: }
146: }
147: // 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. 36. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 498:
499: test("reads KCODE_API_KEY from env", async () => {
500: process.env.KCODE_API_KEY = "sk-env-key";
501: const settings = await loadSettings(tempDir);
502: expect(settings.apiKey).toBe("sk-env-key");
503: });Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 37. 🟠 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 (+9 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 38. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 22: "KCODE_FF_ENABLE_EXPERIMENTAL_TOOLS",
23: ]) {
24: savedEnv[key] = process.env[key];
25: delete process.env[key];
26: }
27: });Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 39. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 59: if (settingsFlags) {
60: for (const key of Object.keys(flags) as (keyof RuntimeFeatureFlags)[]) {
61: if (key in settingsFlags && typeof settingsFlags[key] === "boolean") {
62: flags[key] = settingsFlags[key] as boolean;
63: }
64: }Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 40. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 89: }
90:
91: meta[key] = parseYamlValue(value);
92: }
93: }
94: Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 41. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 8: // ─── Real Server Setup ──────────────────────────────────────────
9:
10: const TEST_API_KEY = "e2e-test-key-" + Date.now();
11: let server: ReturnType<typeof Bun.serve> | null = null;
12: let BASE = "";
13: let serverAvailable = false;Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 42. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 304: }
305:
306: config.installed[name] = {
307: version: plugin.version,
308: installedAt: new Date().toISOString(),
309: };Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 43. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 130: if (DANGEROUS_KEYS.has(key)) continue;
131: if (typeof value === "string" && value.length > MAX_STRING_FIELD_SIZE) {
132: result[key] =
133: value.slice(0, MAX_STRING_FIELD_SIZE) + `\n[Truncated at ${MAX_STRING_FIELD_SIZE} bytes]`;
134: } else if (value !== null && typeof value === "object" && !Array.isArray(value)) {
135: result[key] = sanitizeMcpInput(value as Record<string, unknown>, depth + 1);Verification: Verification skipped — static-only mode (+5 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 44. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 198: const data: Record<string, TokenStorageEntry> = {};
199: for (const [key, entry] of store) {
200: data[key] = {
201: ...entry,
202: tokens: encryptTokens(entry.tokens as OAuthTokens),
203: 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. 45. 🟠 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 (+1 more matches of this pattern in the same file) Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 46. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 92: describe("buildAuthHeaders", () => {
93: test("includes X-Team-Token and Content-Type", () => {
94: const token = "test-token-123";
95: const headers = buildAuthHeaders(token);
96: expect(headers["X-Team-Token"]).toBe(token);
97: expect(headers["Content-Type"]).toBe("application/json");Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 47. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 53: test("loads config from env vars", async () => {
54: process.env.STRIPE_SECRET_KEY = "sk_test_abc123";
55: process.env.STRIPE_WEBHOOK_SECRET = "whsec_test_xyz";
56: process.env.STRIPE_PRICE_ID = "price_test_pro";
57: process.env.STRIPE_PORTAL_RETURN_URL = "https://kulvex.ai/dashboard";
58: Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 48. 🟠 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. 49. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 217: writeFileSync(join(pluginDir, "plugin.json"), JSON.stringify(manifest, null, 2), "utf-8");
218:
219: config.installed[name] = {
220: version: plugin.version,
221: installedAt: new Date().toISOString(),
222: };Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 50. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 24: const restore = (key: string, val: string | undefined) => {
25: if (val === undefined) delete process.env[key];
26: else process.env[key] = val;
27: };
28: restore("KCODE_PROFILE", savedProfile);
29: restore("KCODE_PROFILE_STARTUP", savedStartup);Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 51. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 34:
35: test("GPT model resolves OPENAI_API_KEY", () => {
36: process.env.OPENAI_API_KEY = "sk-openai-test";
37: expect(resolveApiKey("gpt-4", "http://example.com", baseConfig)).toBe("sk-openai-test");
38: });
39: Verification: Verification skipped — static-only mode (+6 more matches of this pattern in the same file) Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 52. 🟠 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. 53. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 23: const restore = (key: string, val: string | undefined) => {
24: if (val === undefined) delete process.env[key];
25: else process.env[key] = val;
26: };
27: restore("KCODE_PROFILE_STARTUP", savedProfileEnv);
28: restore("KCODE_PROFILE", savedProfileEnv2);Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 54. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 7:
8: const BASE_URL = "https://cloud.kulvex.ai/api/v1";
9: const AUTH_TOKEN = "test-token-abc123";
10:
11: const sampleTrigger: RemoteTrigger = {
12: id: "trg_001",Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 55. 🟠 Hardcoded secret/key in JavaScript/TypeScript — CWE-798File: Why this matters: Code: 7:
8: const BASE_URL = "https://cloud.kulvex.ai/api/v1";
9: const AUTH_TOKEN = "test-token-abc123";
10:
11: const sampleTrigger: RemoteTrigger = {
12: id: "trg_001",Verification: Verification skipped — static-only mode Fix template: Use process.env.SECRET_KEY or a secrets manager. 56. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 40: // Hash path fields
41: for (const field of PATH_FIELDS) {
42: if (typeof attrs[field] === "string") {
43: attrs[`${field}_hash`] = sha256Short(attrs[field] as string);
44: delete attrs[field];
45: }Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 57. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 31:
32: // Look for an explicit rate for this event name
33: const rate = typeof config[name] === "number" ? (config[name] as number) : config.default;
34:
35: if (rate >= 1) return true;
36: if (rate <= 0) return 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. 58. 🟠 Hardcoded secret or API key in JavaScript/TypeScript — CWE-798File: Why this matters: Code: 22: fallbackModel: null,
23: pro: false,
24: apiKey: "sk-secret-key-do-not-expose",
25: anthropicApiKey: "secret-anthropic-key",
26: }),
27: getUsage: () => ({Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use process.env.API_KEY or a secrets manager. Never commit real keys. 59. 🟠 Prototype pollution via bracket notation with user key — CWE-1321File: Why this matters: Code: 63: while ((match = re.exec(content)) !== null) {
64: var name = match[1];
65: usage[name] = (usage[name] || 0) + 1;
66: }
67: }
68: this.toolUsage = usage;Verification: Verification skipped — static-only mode Fix template: Validate keys: if (['proto', 'constructor', 'prototype'].includes(key)) return; or use Map instead of plain objects. 60. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 70:
71: AnalyticsDashboard.prototype.render = function () {
72: this.container.innerHTML = "";
73:
74: var wrapper = document.createElement("div");
75: wrapper.className = "dashboard-panel analytics-dashboard";Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 61. 🟠 Hardcoded password, secret, or API key — CWE-798File: Why this matters: Code: 173: var proto = window.location.protocol === "https:" ? "wss:" : "ws:";
174: this.wsUrl =
175: proto + "//" + window.location.host + "/ws?token=" + encodeURIComponent(this.authToken);
176: };
177:
178: KCodeWebUI.prototype.connect = function () {Verification: Verification skipped — static-only mode Fix template: Move to environment variable: os.environ.get('SECRET_KEY') 62. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 355: var rendered = window.MarkdownRenderer.renderMarkdown(msg.content);
356: if (window.DOMPurify) {
357: body.innerHTML = window.DOMPurify.sanitize(rendered);
358: } else {
359: body.innerHTML = rendered;
360: }Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 63. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 42:
43: ConfigPanel.prototype.render = function () {
44: this.container.innerHTML = "";
45:
46: var wrapper = document.createElement("div");
47: wrapper.className = "dashboard-panel config-panel";Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 64. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 44:
45: ModelDashboard.prototype.render = function () {
46: this.container.innerHTML = "";
47:
48: var wrapper = document.createElement("div");
49: wrapper.className = "dashboard-panel model-dashboard";Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 65. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 46:
47: SessionViewer.prototype.render = function () {
48: this.container.innerHTML = "";
49:
50: var wrapper = document.createElement("div");
51: wrapper.className = "dashboard-panel session-viewer";Verification: Verification skipped — static-only mode (+4 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 66. 🟠 innerHTML/outerHTML with dynamic content (XSS) — CWE-79File: Why this matters: Code: 507: // Sanitize markdown output to prevent XSS from model-generated content
508: const rendered = formatMarkdown(content);
509: div.innerHTML = typeof DOMPurify !== 'undefined' ? DOMPurify.sanitize(rendered) : rendered;
510: } else {
511: div.textContent = content;
512: }Verification: Verification skipped — static-only mode (+3 more matches of this pattern in the same file) Fix template: Use element.textContent = value, or DOMPurify.sanitize(html). 67. 🟠 innerHTML assignment with dynamic content (XSS) — CWE-79File: Why this matters: Code: 592: const toolDiv = document.createElement('div');
593: toolDiv.className = 'tool-indicator' + (msg.isError ? ' error' : '');
594: toolDiv.innerHTML = '<span class="tool-name">' + escapeHtml(msg.name) + '</span>';
595: if (msg.result) {
596: const resultText = typeof msg.result === 'string'
597: ? msg.result.slice(0, 200)Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Use textContent for text, or sanitize: el.innerHTML = DOMPurify.sanitize(html). 68. 🟡 Retain cycle: strong reference in closure without [weak self] — CWE-401File: Why this matters: Code: 22: }
23:
24: init() {
25: self.serverURL = UserDefaults.standard.string(forKey: "serverURL") ?? "http://localhost:10100"
26: self.model = UserDefaults.standard.string(forKey: "model") ?? "claude-opus-4-6"
27: self.cwd = UserDefaults.standard.string(forKey: "cwd") ?? ""Verification: Verification skipped — static-only mode Fix template: Add [weak self] or [unowned self] capture list: { [weak self] in guard let self else { return } ... } 69. 🟡 Retain cycle: strong reference in closure without [weak self] — CWE-401File: Why this matters: Code: 32: }
33:
34: struct ChatMessage: Identifiable {
35: let id = UUID()
36: let role: MessageRole
37: let kind: MessageKindVerification: Verification skipped — static-only mode Fix template: Add [weak self] or [unowned self] capture list: { [weak self] in guard let self else { return } ... } 70. 🟡 Retain cycle: strong reference in closure without [weak self] — CWE-401File: Why this matters: Code: 27: private var settings: AppSettings?
28:
29: func configure(settings: AppSettings) {
30: self.settings = settings
31: }
32: Verification: Verification skipped — static-only mode (+4 more matches of this pattern in the same file) Fix template: Add [weak self] or [unowned self] capture list: { [weak self] in guard let self else { return } ... } 71. 🟡 Missing error handling in async/await — CWE-755File: Why this matters: Code: 127: // Reset mood after 2s
128: Task { @MainActor in
129: try? await Task.sleep(nanoseconds: 2_000_000_000)
130: if self.kodiMood == .done { self.kodiMood = .idle }
131: }
132: Verification: Verification skipped — static-only mode Fix template: Wrap in do/catch: do { let result = try await fetchData() } catch { handleError(error) } 72. 🟡 Retain cycle: strong reference in closure without [weak self] — CWE-401File: Why this matters: Code: 20: }
21:
22: class SSEClient: NSObject, URLSessionDataDelegate {
23: weak var delegate: SSEClientDelegate?
24: private var dataTask: URLSessionDataTask?
25: private var buffer = Data()Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Add [weak self] or [unowned self] capture list: { [weak self] in guard let self else { return } ... } 73. 🟡 Missing error handling in async/await — CWE-755File: Why this matters: Code: 100: }
101: do {
102: let (_, response) = try await URLSession.shared.data(from: url)
103: if let http = response as? HTTPURLResponse, http.statusCode == 200 {
104: testResult = "✓ Connected"
105: } else {Verification: Verification skipped — static-only mode Fix template: Wrap in do/catch: do { let result = try await fetchData() } catch { handleError(error) } 74. 🟡 Security-related TODO/FIXME/HACK comment — CWE-1035File: Why this matters: Code: 1087: // ── Universal ──────────────────────────────────────────────
1088: "uni-001-hardcoded-ip": r("hardcoded IP", "Move the IP address to config — hardcoding makes deployment brittle."),
1089: "uni-002-security-todo": r("security TODO", "Address this security TODO before shipping."),
1090:
1091: // ── Zig ────────────────────────────────────────────────────
1092: "zig-001-use-after-free": r("use-after-free", "Don't use memory after free — null the pointer or use defer."),Verification: Verification skipped — static-only mode Fix template: Address the security concern or remove the stale comment. 75. 🟡 window.location set from user input (open redirect) — CWE-601File: Why this matters: Code: 802: cwe: "CWE-601",
803: fix_template:
804: "Validate redirect URL against allowlist: const allowed = ['/dashboard', '/home']; if (allowed.includes(url)) location.href = url;",
805: },
806: {
807: id: "js-017-hardcoded-secret-inline",Verification: Verification skipped — static-only mode Fix template: Validate redirect URL against allowlist: const allowed = ['/dashboard', '/home']; if (allowed.includes(url)) location.href = url; 76. 🟡 document.write() usage (XSS vector, performance issue) — CWE-79File: Why this matters: Code: 821: {
822: id: "js-018-document-write",
823: title: "document.write() usage (XSS vector, performance issue)",
824: severity: "medium",
825: languages: ["javascript", "typescript"],
826: regex: /\bdocument\.write(?:ln)?\s*\(/g,Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Use DOM APIs: document.createElement() + appendChild(), or element.textContent for text. 77. 🟡 Security-related TODO/FIXME/HACK comment — CWE-1035File: Why this matters: Code: 2189: verify_prompt: "Is this a real connection string with credentials or a placeholder? If real, respond CONFIRMED." +
2190: "\n\nRespond FALSE_POSITIVE if ANY of these is true:\n" +
2191: "1. The password is a placeholder ('changeme', 'xxx', 'password', 'TODO', 'REPLACE_ME')\n" +
2192: "2. This is in test, example, or documentation code\n" +
2193: "3. The connection string is loaded from configuration/environment at runtime\n" +
2194: "4. This is a local development connection (localhost with default credentials)\n" +Verification: Verification skipped — static-only mode (+5 more matches of this pattern in the same file) Fix template: Address the security concern or remove the stale comment. 78. 🟡 Promise chain without .catch() (unhandled rejection) — CWE-755File: Why this matters: Code: 771: }
772: };
773: _settingsSaveLock = _settingsSaveLock.then(op, op);
774: return _settingsSaveLock;
775: }
776: Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Add .catch(err => { /* handle */ }) at the end of the chain, or use async/await with try/catch. 79. 🟡 Security-related TODO/FIXME/HACK comment — CWE-1035File: Why this matters: Code: 118: /(["']?(?:api[_-]?key|secret|token|password|authorization|bearer|credential|private[_-]?key|access[_-]?key)["']?\s*[:=]\s*["']?)([^\s"',}{[\]]{8,})/gi;
119:
120: /** API keys embedded in URLs (e.g., ?key=xxx or &token=xxx) */
121: private static readonly URL_KEY_RE =
122: /([?&](?:key|token|api_key|apikey|access_token|secret|password)=)([^\s&"']{8,})/gi;
123: Verification: Verification skipped — static-only mode Fix template: Address the security concern or remove the stale comment. 80. 🟡 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 */ } 81. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 463:
464: const PORT = Number(process.env.PORT) || 10080;
465: const HOST = process.env.HOST ?? "0.0.0.0";
466:
467: console.log(`KCode Backend starting on ${HOST}:${PORT}`);
468: Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 82. 🟢 addEventListener without corresponding removeEventListener — CWE-401File: Why this matters: Code: 369: }
370:
371: sendBtn.addEventListener('click', send);
372: inputEl.addEventListener('keydown', (e) => {
373: if (e.key === 'Enter' && !e.shiftKey) {
374: e.preventDefault();Verification: Verification skipped — static-only mode Fix template: Store reference and remove in cleanup: const handler = () => {}; el.addEventListener('click', handler); // later: el.removeEventListener('click', handler); 83. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 6: .description("Start KCode as an HTTP API server")
7: .option("-p, --port <port>", "Port to listen on", (v: string) => parseInt(v, 10), 10101)
8: .option("-h, --host <host>", "Host to bind to", "127.0.0.1")
9: .option("--api-key <key>", "Require this API key for authentication")
10: .action(async (opts: { port?: number; host?: string; apiKey?: string }) => {
11: try {Verification: Verification skipped — static-only mode (+3 more matches of this pattern in the same file) Fix template: Move to configuration file or environment variable. 84. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 14: .description("Start the browser-based Web UI")
15: .option("-p, --port <port>", "Port to listen on", (v: string) => parseInt(v, 10))
16: .option("--host <host>", "Host to bind to", "127.0.0.1")
17: .option("--no-open", "Don't open browser automatically")
18: .option("--no-auth", "Disable token authentication (insecure)")
19: .action(async (opts: { port?: number; host?: string; open?: boolean; auth?: boolean }) => {Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Move to configuration file or environment variable. 85. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 95:
96: # Flags
97: if [[ "$cur" == -* ]]; then
98: COMPREPLY=($(compgen -W "${flags} ${shorts}" -- "$cur"))
99: return
100: fiVerification: Verification skipped — static-only mode (+3 more matches of this pattern in the same file) Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 86. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 144: severity: "high",
145: languages: ["c", "cpp"],
146: // Match ptr->field followed by if (ptr == NULL) within 100 chars,
147: // BUT exclude when there's a return/break/goto between them
148: // (those exit the scope, so the null check is for a different path).
149: regex: /\b(\w+)\s*->\s*\w+(?![\s\S]{0,100}?\b(?:return|break|goto)\b)[\s\S]{0,100}?\bif\s*\(\s*\1\s*(?:==|!=)\s*(?:NULL|nullptr|0)\s*\)/g,Verification: Verification skipped — static-only mode (+20 more matches of this pattern in the same file) Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 87. 🟢 addEventListener without corresponding removeEventListener — CWE-401File: Why this matters: Code: 741: cwe: "CWE-401",
742: fix_template:
743: "Store reference and remove in cleanup: const handler = () => {}; el.addEventListener('click', handler); // later: el.removeEventListener('click', handler);",
744: },
745: {
746: id: "js-013-loose-equality",Verification: Verification skipped — static-only mode Fix template: Store reference and remove in cleanup: const handler = () => {}; el.addEventListener('click', handler); // later: el.removeEventListener('click', handler); 88. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 65: * Compare two semver strings. Returns:
66: * -1 if a < b
67: * 0 if a == b
68: * 1 if a > b
69: */
70: export function compareSemver(a: string, b: string): number {Verification: Verification skipped — static-only mode Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 89. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 306: server.close(() => resolve(true));
307: });
308: server.listen(10101, "127.0.0.1");
309: });
310: if (portAvailable) {
311: results.push({ name: "HTTP server port", status: "ok", message: "Port 10101 is available" });Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 90. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 35: export const DEFAULT_EXTENSION_API_CONFIG: ExtensionApiConfig = {
36: port: 19300,
37: host: "127.0.0.1",
38: rateLimit: 60,
39: corsOrigins: ["*"],
40: };Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 91. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 223: if (/^169\.254\./.test(h)) return true;
224: // Cloud provider metadata endpoints (AWS/GCP link-local + Azure wireserver)
225: if (h === "168.63.129.16") return true; // Azure Instance Metadata / wireserver
226: if (/^100\.(6[4-9]|[7-9]\d|1[01]\d|12[0-7])\./.test(h)) return true; // AWS VPC carrier-grade NAT (100.64-127.x)
227: if (/^0\./.test(h) || h === "0.0.0.0") return true;
228: if (h === "::1" || h === "[::1]") return true;Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Move to configuration file or environment variable. 92. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 1029: // Default to loopback — binding to 0.0.0.0 without auth is RCE from the network
1030: const host =
1031: options.host === "0.0.0.0" || options.host === "::"
1032: ? options.host
1033: : options.host || "127.0.0.1";
1034: const isExposed = host === "0.0.0.0" || host === "::";Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Move to configuration file or environment variable. 93. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 126: mx.set_wired_limit = lambda *a, **kw: _orig(${wiredBytes})
127: import sys
128: sys.argv = ['mlx_lm.server', '--model', '${safeModel}', '--port', '${safePort}', '--host', '127.0.0.1']
129: from mlx_lm.server import main
130: main()`;
131: args = ["-c", wrapperScript];Verification: Verification skipped — static-only mode (+2 more matches of this pattern in the same file) Fix template: Move to configuration file or environment variable. 94. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 75: if (
76: parsed.protocol === "http:" &&
77: (host === "localhost" || host === "127.0.0.1" || host === "::1")
78: )
79: return;
80: throw new Error(Verification: Verification skipped — static-only mode (+1 more matches of this pattern in the same file) Fix template: Move to configuration file or environment variable. 95. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 75: parsed.protocol === "http:" &&
76: (parsed.hostname === "localhost" ||
77: parsed.hostname === "127.0.0.1" ||
78: parsed.hostname === "::1");
79: if (parsed.protocol !== "https:" && !isLocalhost) return false;
80: } catch {Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 96. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 7: // ─── Constants ─────────────────────────────────────────────────
8:
9: const MDNS_MULTICAST_ADDR = "224.0.0.251";
10: const MDNS_PORT = 5353;
11: const KCODE_SERVICE_TYPE = "_kcode-mesh._tcp";
12: const ANNOUNCE_INTERVAL_MS = 30_000; // Re-announce every 30sVerification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 97. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 288: nodeId: this.nodeId,
289: hostname: this.hostname,
290: ip: "127.0.0.1",
291: port: this.settings.port,
292: capabilities: { ...this.capabilities },
293: status: this._status === "running" ? "online" : "offline",Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 98. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 153: postCreate: "python -m venv venv && source venv/bin/activate && pip install fastapi uvicorn",
154: files: {
155: "main.py": `from fastapi import FastAPI\n\napp = FastAPI(title="{{name}}")\n\n@app.get("/health")\ndef health():\n return {"status": "ok"}\n\n@app.get("/api/hello")\ndef hello(name: str = "world"):\n return {"message": f"Hello, {name}!"}\n\nif __name__ == "__main__":\n import uvicorn\n uvicorn.run(app, host="0.0.0.0", port=10080)\n`,
156: "requirements.txt": "fastapi>=0.115.0\nuvicorn>=0.34.0\n",
157: ".gitignore": "venv/\n__pycache__/\n*.pyc\n.env\n",
158: },Verification: Verification skipped — static-only mode Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 99. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 153: postCreate: "python -m venv venv && source venv/bin/activate && pip install fastapi uvicorn",
154: files: {
155: "main.py": `from fastapi import FastAPI\n\napp = FastAPI(title="{{name}}")\n\n@app.get("/health")\ndef health():\n return {"status": "ok"}\n\n@app.get("/api/hello")\ndef hello(name: str = "world"):\n return {"message": f"Hello, {name}!"}\n\nif __name__ == "__main__":\n import uvicorn\n uvicorn.run(app, host="0.0.0.0", port=10080)\n`,
156: "requirements.txt": "fastapi>=0.115.0\nuvicorn>=0.34.0\n",
157: ".gitignore": "venv/\n__pycache__/\n*.pyc\n.env\n",
158: },Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 100. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 46: let padded = str.replace(/-/g, "+").replace(/_/g, "/");
47: const mod = padded.length % 4;
48: if (mod === 2) padded += "==";
49: else if (mod === 3) padded += "=";
50: return Buffer.from(padded, "base64");
51: }Verification: Verification skipped — static-only mode Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 101. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 301: const isLocalModel =
302: apiBase.includes("localhost") ||
303: apiBase.includes("127.0.0.1") ||
304: apiBase.startsWith("http://[::1]");
305: const toolOverhead = estimateToolDefinitionTokens(tools, profileToolFilter ?? undefined);
306: if ((isLocalModel || toolOverhead > contextWindow * 0.15) && !profileToolFilter) {Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 102. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 50: const added = newCount - oldCount;
51:
52: // Check: did the old string compensate by having `cmp(...) == 0` that the
53: // new string converted to `!cmp(...)`? That's a stylistic change, not an
54: // inversion. Look for `(str|wcs|...)cmp\([^)]*\)\s*==\s*0` pattern in old.
55: const cmpEqZeroRegex =Verification: Verification skipped — static-only mode (+4 more matches of this pattern in the same file) Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 103. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 149: - "no bugs found" when you read fewer than 10 files
150: - Findings with "Status: Requires runtime testing" — if you couldn't verify it, DON'T list it
151: - Speculative/defensive bugs ("what if a listener isn't deregistered", "if neutral == min this would divide by zero") — these are architectural suggestions, not verified bugs. Only list bugs you can point to in actual code paths that WILL execute.
152: - Marketing language of any kind
153: - A final "Verdict" or "Conclusion" that grades the code as safe/approved/ready — just list the findings and stop. The user decides if the code is ready.
154: - Multiple report files. ONE file only: \`AUDIT_REPORT.md\`. Never also create FIXES_SUMMARY.txt, AUDIT_INDEX.md, REMEDIATION_FIXES.md, README_AUDIT.txt, FIXES_APPLIED.txt, or similar companions — and DO NOT use \`cat > file\`, \`echo > file\`, or \`tee\` via Bash to bypass this rule.Verification: Verification skipped — static-only mode Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 104. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 105: const isLocal =
106: apiBase.includes("localhost") ||
107: apiBase.includes("127.0.0.1") ||
108: apiBase.startsWith("http://[::1]");
109: if (isLocal && userMessage) {
110: try {Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 105. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 252: model_name=BASE_MODEL,
253: max_seq_length=4096,
254: load_in_4bit=(QUANT == "4bit"),
255: )
256:
257: print(f"Applying LoRA (rank={LORA_RANK})")Verification: Verification skipped — static-only mode (+4 more matches of this pattern in the same file) Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 106. 🟢 Loose equality (==) instead of strict equality (===) — CWE-697File: Why this matters: Code: 30: * Compare two semver strings. Returns:
31: * -1 if a < b
32: * 0 if a == b
33: * 1 if a > b
34: */
35: function compareSemver(a: string, b: string): number {Verification: Verification skipped — static-only mode Fix template: Use === for strict equality, or == null specifically for null/undefined checks. 107. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 1286: if (
1287: hostname === "localhost" ||
1288: hostname === "127.0.0.1" ||
1289: hostname === "::1" ||
1290: hostname.startsWith("169.254.") ||
1291: hostname.startsWith("10.") ||Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 108. 🟢 Hardcoded IP address or internal URL — CWE-798File: Why this matters: Code: 77: export const DEFAULT_WEB_CONFIG: WebServerConfig = {
78: port: 19300,
79: host: "127.0.0.1",
80: auth: {
81: enabled: true,
82: token: crypto.randomUUID(),Verification: Verification skipped — static-only mode Fix template: Move to configuration file or environment variable. 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 |
…ern + v2.10.63 Self-audit of phases 17-24 found two real bugs and one test-quality issue that needed fixing. This commit addresses all three. Bug #1 — phase 22 auto-launch notice was never shown to the user. conversation.ts:1921 yielded `{ type: "text", text: ... }` but the StreamEvent union has no "text" variant — the correct variant is "text_delta", handled by print-mode.ts and stream-handler.ts. The TypeScript error was visible in typecheck but I'd dismissed it as pre-existing noise from conversation.ts's other errors. Result: the notice was stored in state.messages (model sees it next turn) but silently dropped before reaching the terminal (user never sees the launch URL or stop instructions — the entire point of phase 22). Fix is a one-word change to the event type. Bug #2 — phase 24 didn't cover `node server.js`. The initial phase 24 added detectServerSpawn fallback to bash.ts, but detectServerSpawn itself had no regex for bare `node <file>.js` invocations. `npm run dev` was covered, but if the model ran `node server.js` directly (exactly what the Orbital prompt set up), the command still got killed at 4s. Fix: add node-direct and bun-direct patterns matched on a filename allowlist (server, app, index, main) so one-shot scripts like `node scripts/migrate.js` still stay in the foreground. Test-quality fix — the phase 24 tests in bash.test.ts were tautologies. All six tests used `echo 'would run X' && exit 0` as a stand-in for the real command, and echo exits in <20ms so the elapsed-time assertion passed whether the fix was present or not. They validated nothing. Removed them in favor of direct unit tests on detectServerSpawn in bash-spawn-verifier.test.ts, where the decision logic is pure and actually testable. 9 new positive cases (node server.js, node app.js, node index.js, node main.js, node src/server.js, node ./server.mjs, node server.cjs, bun server.ts, bun run app.ts) and 5 new negatives (node scripts/ migrate.js, benchmarks/bench.js, tools/generate.js, build.js, ./scripts/cleanup.cjs). Full regression: 122/122 pass in bash.test.ts + bash-spawn-verifier.test.ts. Phase 22 auto-launch-dev-server tests and phase 23 repetition-detector tests also green. Co-Authored-By: Kulvex Code <contact@astrolexis.space>
Self-review of the previous /fix overhaul surfaced six issues. Three were high-severity correctness bugs that could silently corrupt user code; three were medium-severity correctness/robustness bugs. All six are closed here with targeted tests. HIGH #1 — fixDartJsonNullCheck over-matched The regex `/\\bas\\s+(int|double|num|bool|String)\\b(?!\\?)/g` had no context requirement, so it rewrote any primitive cast on any line: final count = users.length as int; // ← was getting rewritten final x = someCall() as String; // ← was getting rewritten Business-logic casts that had nothing to do with JSON were silently turned into `as int? ?? 0` / `as String? ?? ''`, changing runtime behavior (exception → default value). The fix tightens the regex to require a `json['key']` subscript immediately preceding the `as`: /(\\bjson\\s*\\[\\s*['"][^'"]+['"]\\s*\\]\\s*as\\s+(int|...))\\b(?!\\?)/g Only casts that live inside the exact `json[...] as T` shape are rewritten now. A regression test (mixed.dart) exercises a file with both kinds of casts and asserts the non-json ones are untouched. HIGH #2 — whole-file sweep amplified false positives The dart-007 fixer sweeps the entire file (needed because the audit engine dedupes repeated matches of the same pattern+file into a single Finding, so only the first line is reported). Combined with HIGH #1, a single false-positive finding could rewrite every cast in the file. Narrowing the regex in #1 largely addresses this — the sweep now only touches lines that contain the literal `json['...']` subscript, so the blast radius is bounded to fromJson factories. HIGH #3 — writeFileSync was not atomic if (modified) { writeFileSync(file, lines.join("\\n")); } A crash mid-write (Ctrl-C, OOM, disk full, process kill) left the user's source file half-corrupted with no recovery. Introduced `atomicWriteFileSync()`: write to `<target>.kcode-fix-<rand>.tmp` then `renameSync` over the target. The rename is atomic on POSIX since the temp file is in the same directory. On rename failure the temp file is cleaned up and the error propagates. MEDIUM #4 — setState guard detection short-window fixDartSetStateAfterDispose only looked at the 3 non-blank lines immediately before `setState(` for a mounted/disposed guard. A valid guard placed just after the `await` but separated from the setState by comments or blank lines was missed, causing a duplicate guard to be inserted. Replaced the short lookback with a full-span walk from the await line (finding.line) to the setState call. Regression test state.dart exercises a 6-line gap and asserts exactly one guard. MEDIUM #5 — dart-005 assumed `mounted` always exists The fixer inserted `if (!mounted) return;` without verifying the enclosing class is a State<T> subclass. In rare cases (helper classes, mixins, non-Flutter Dart with a local `setState` method) `mounted` is undefined and the inserted guard fails to compile. Added `isInsideFlutterState()` which walks backward looking for a `class X extends ... State<...>` declaration; if not found within 400 lines, the fix is skipped with an explanatory message. Regression test helper.dart has a non-State class named `NotAState` and asserts no guard is inserted. MEDIUM #6 — scanner could escape the project root and loop on cyclic symlinks findSourceFiles used readdirSync + statSync, which follows symlinks silently. A link pointing outside the audited project leaked files from unrelated directories into the scan; a cyclic link (a→b→a or link→.) would walk forever until file-descriptor exhaustion. Scanner now: - Resolves the project root to a realpath once at start. - Resolves every directory AND file via realpath before visiting. - Rejects resolved paths that don't equal or start with `<projectRealpath>/` — closes the root-escape hole. - Tracks visited directories and files in two Sets keyed by real path — closes the cycle-loop hole. Two regression tests in audit-engine.test.ts create sibling directories with escaping and cyclic symlinks and assert the scanner neither leaks outside files nor loops. Both tests degrade gracefully on platforms where symlink creation requires privileges. Bump to v2.10.11. Audit-engine suite now has 33 passing tests (was 28) covering all six holes. Co-Authored-By: Kulvex Code <contact@astrolexis.space>
audit: overhaul /fix honesty, per-ecosystem filters, scanner safety (v2.10.6 → v2.10.13)
…ern + v2.10.63 Self-audit of phases 17-24 found two real bugs and one test-quality issue that needed fixing. This commit addresses all three. Bug #1 — phase 22 auto-launch notice was never shown to the user. conversation.ts:1921 yielded `{ type: "text", text: ... }` but the StreamEvent union has no "text" variant — the correct variant is "text_delta", handled by print-mode.ts and stream-handler.ts. The TypeScript error was visible in typecheck but I'd dismissed it as pre-existing noise from conversation.ts's other errors. Result: the notice was stored in state.messages (model sees it next turn) but silently dropped before reaching the terminal (user never sees the launch URL or stop instructions — the entire point of phase 22). Fix is a one-word change to the event type. Bug #2 — phase 24 didn't cover `node server.js`. The initial phase 24 added detectServerSpawn fallback to bash.ts, but detectServerSpawn itself had no regex for bare `node <file>.js` invocations. `npm run dev` was covered, but if the model ran `node server.js` directly (exactly what the Orbital prompt set up), the command still got killed at 4s. Fix: add node-direct and bun-direct patterns matched on a filename allowlist (server, app, index, main) so one-shot scripts like `node scripts/migrate.js` still stay in the foreground. Test-quality fix — the phase 24 tests in bash.test.ts were tautologies. All six tests used `echo 'would run X' && exit 0` as a stand-in for the real command, and echo exits in <20ms so the elapsed-time assertion passed whether the fix was present or not. They validated nothing. Removed them in favor of direct unit tests on detectServerSpawn in bash-spawn-verifier.test.ts, where the decision logic is pure and actually testable. 9 new positive cases (node server.js, node app.js, node index.js, node main.js, node src/server.js, node ./server.mjs, node server.cjs, bun server.ts, bun run app.ts) and 5 new negatives (node scripts/ migrate.js, benchmarks/bench.js, tools/generate.js, build.js, ./scripts/cleanup.cjs). Full regression: 122/122 pass in bash.test.ts + bash-spawn-verifier.test.ts. Phase 22 auto-launch-dev-server tests and phase 23 repetition-detector tests also green. Co-Authored-By: Kulvex Code <contact@astrolexis.space>
External audit surfaced four real issues across the codebase. All four confirmed, all four fixed. ## HIGH #1: /web can rm -rf src/ of an existing user repo src/core/web-engine/web-engine.ts:91-98 detected package.json / go.mod / Cargo.toml in cwd and then set projectPath=cwd followed by rmSync(srcPath, { recursive: true, force: true }). If the user ran /web from inside their own repo, their src/ was silently deleted. Real data-loss vector. Fix: introduce a .kcode-generated marker file. The rm path now runs ONLY when the target is KCode-owned: cwdIsKcodeGenerated → safe to re-scaffold in place cwdHasProject (user) → scaffold into cwd/intent.name instead; if that exists and is NOT kcode-generated, throw 'Refusing to scaffold into X' so the user has to explicitly clear the path. empty cwd → cwd/intent.name as before. The rm is further gated by the same marker check — never wipes a non-kcode src/. ## HIGH #2: /fix applies changes from unverified findings src/ui/actions/file-actions-audit.ts:251 re-ran the scan with skipVerification:true and a hardcoded llmCallback that returned 'CONFIRMED' for every candidate when AUDIT_REPORT.json was missing, then handed those to applyFixes(). applyFixes() is contractually for 'confirmed findings only' (see fixer.ts:64). Net effect: regex false positives got patched into user code. Fix: /fix now refuses to run without a real verified AUDIT_REPORT.json. Also added a pre-filter that inspects each finding's verification.verdict and passes only 'confirmed' to applyFixes() — mixed reports can't leak unverified findings. Workflow chain (stepFix) had the same bug: it wrote a skip- verified report and then called applyFixes() on the whole thing. Now stepFix filters to findings where verdict === 'confirmed' AND reasoning !== 'static-only'. If the set is empty, the step reports 'skipped — no model-verified findings' instead of applying. ## MEDIUM #3: Daemon zombie state on bind failure src/bridge/daemon.ts wrote PID/PORT/TOKEN files BEFORE starting the WebSocket server. If wsServer.start(port) threw (EADDRINUSE, race, etc.), those files persisted pointing at our live process — isDaemonRunning() returned true forever until the user cleaned up manually. Fix: reordered. Initialize components, call wsServer.start() inside a try/catch, and only write state files after the bind succeeds. If bind fails, throw with a clear message and leave no state behind. ## MEDIUM #4: Web UI auth token leaked via URL + logs src/web/server.ts:167 embedded the token in the URL query string, passed it to openBrowser() (xdg-open/open process args), and log.info()'d the full token to the log file. Leaked surfaces: - browser history / bookmark sync - process table (xdg-open receives full URL) - ~/.kcode/logs/*.log on disk - terminal scrollback + any screenshot Fix: switch URL format from ?token=... to #auth=... (fragment). Fragments are never sent to servers, never logged by access logs, and modern browsers don't sync them. The client-side bootstrap already supports the #auth= handoff (strips it into localStorage on first load). Log line now redacts to first 4 + last 2 chars with a placeholder: before: Auth token: BSA-abcd1234...xyz0 after: Auth token: BSA-…z0 (redacted) Query-param acceptance on the API (/api/* ?token=) remains as-is for backward compat with scripts that use it, but the UI handoff path no longer generates those URLs. ## Tests bun test src/core/web-engine/ + fixer/ + task-orchestrator/ + bridge/ + web/server.test.ts → 165/165 pass on affected modules. Note on the suite-wide 142 failures the auditor flagged: those are pre-existing benchmarks/mock-server port collisions and global-state tests unrelated to this change. Scoping the test run to the files I touched keeps feedback tight; a separate pass is needed to stabilize those other suites. Build: 6.54 MB. Refs: external audit Findings 1-4 Co-Authored-By: Kulvex Code <contact@astrolexis.space>
… (tree-sitter)
External roadmap Phase 2: "AST-based matching: queries semánticas
como 'loop que indexa array miembro sin assert en configure() del
mismo archivo'". This sprint ships the contract + lazy runner + one
demonstration pattern. Grammars and more patterns land in follow-up
sprints — the architecture is in place so each addition is a single
file.
Three classes of bugs that AST detection catches but regex can't:
1. Taint flow — pickle.loads(x) is dangerous only when x flows
from a function parameter / request value. Regex sees the
call site; AST traces the assignment chain.
2. Mitigation absence in scope — "loop indexing m_count without
FW_ASSERT(idx < m_max) in the configure() of the same class".
Negative-lookahead gymnastics don't compose; AST queries the
class body in one pass.
3. Type-system invariants — `reinterpret_cast<T*>(buf)` is safer
when buf came from a checked-size source. AST sees the chain.
New surface:
src/core/audit-engine/ast/types.ts
AstPattern { id, query, match, ... } — the declarative shape.
Queries are tree-sitter S-expressions, match() processes the
captures into a Candidate.
src/core/audit-engine/ast/runner.ts
runAstPatterns(patterns, file, content) — dynamically imports
web-tree-sitter at first use, gracefully degrades if absent.
Lazy-loads grammars from $KCODE_GRAMMARS_DIR / ~/.kcode/grammars/
/ bundled location. Missing grammar → structured stat entry,
never an exception. Same Candidate output as the regex pipeline.
src/core/audit-engine/ast/python-patterns.ts
py-ast-001-eval-of-parameter — first AST pattern. Detects
eval/exec/compile whose argument tree-sitter analysis traces
back to a parameter of the enclosing function_definition. Where
regex can only see the call, AST proves the taint chain.
Wiring into runAudit:
Phase 1b after regex scanning runs all AST patterns over the same
file list. Candidates merge into the dedupe pool; verifier and
fixer treat them identically (annotation recipe registered for
py-ast-001 in fixer.ts).
Operational properties:
- Zero runtime cost when web-tree-sitter is not installed (silent
degrade, regex pipeline unaffected).
- Per-file content cap at 500KB matches the regex scanner.
- Grammar lookup is ENV-overrideable (KCODE_GRAMMARS_DIR) so CI
can mount a shared cache.
Tests: 3 new (runner.test.ts):
- runAstPatterns([]) → empty results, no exceptions.
- With patterns + missing grammar/dep → structured stats with
grammar_loaded=false and load_error populated, no exceptions.
- python-patterns shape (query string, match function, severity,
CWE).
Full suite 719/719 green (3 new + 716 prior).
Next: bundle a Python grammar (~600 KB .wasm) so the demo pattern
fires end-to-end, then expand AST patterns to high-value taint
shapes in JS/TS, Go, Java, C++.
Co-Authored-By: Kulvex Code <contact@astrolexis.space>
Summary
Seven-commit overhaul of the audit engine that takes KCode from v2.10.6 to v2.10.13. Started as "make audit stop reporting false positives in Flutter ephemeral code" and grew into a full review of the /fix pipeline after dogfooding surfaced a serious honesty bug: the previous /fix claimed success for every finding but ~230 of the ~240 patterns only inserted a TODO-style comment and left the bug in place.
Commits in order
3d301ccsh-001language fix2a92947b15e350py-020-global-keywordverify_prompt refined to recognize circuit breakers / rate limiters / connection pools as FALSE_POSITIVEe7a7d8cFixKind = transformed|annotated|skippedfield separates real code transforms from advisory comments. UI shows three buckets. Added 2 real bespoke Dart fixers (dart-007-json-null-check,dart-005-setstate-after-dispose).c63cfa3c2b0be8applyRecipeno longer duplicates annotations on stale re-runs (±3 line window check)f106671McpManager.loadFromConfigs+ unguarded JSON.parse inparseNotebookKey changes
Scanner —
src/core/audit-engine/scanner.tsSKIP_DIRSexpanded from 17 entries to ~55, covering every ecosystem the audit engine understands.SKIP_PATH_SUBSTRINGScatches generated dirs that aren't a literal top-level name (/generated/,/build/intermediates/, etc.).SKIP_FILENAME_PATTERNScatches generated files by basename regex (Dart code-gen, protobuf, Qt moc, C# designer, Swift generated, minified JS/CSS).looksMinified()heuristic skips files whose longest line exceeds 5000 chars.realpathSyncand is checked againstvisitedDirs/visitedFilessets — cyclic symlinks can't loop, and links that escape the project root are rejected.Fixer —
src/core/audit-engine/fixer.tsFixResult/OneFixResultcarry a newkind: "transformed" | "annotated" | "skipped"field.applyRecipe(generic advisory path) returnskind: "annotated"— the buggy code is UNCHANGED; the comment is a TODO.kind: "transformed"— real code is rewritten.dart-007-json-null-check: narrow regex requiresjson['...']context, then rewritesas int|double|num|bool|Stringto the nullable + default form. Whole-file sweep for multi-match files.dart-005-setstate-after-dispose: insertsif (!mounted) return;before setState, with full-span guard detection and class-context verification (only inserts when we're inside aState<T>subclass).atomicWriteFileSync()writes to<target>.kcode-fix-<rand>.tmpthen renames — atomic on POSIX.applyRecipededup guard scans ±3 lines around the insertion point, not justidx - 1— absorbs line drift from stale audit reports.UI —
src/ui/actions/file-actions.ts/fixoutput now has three buckets with distinct icons and counts:✅ Fixed: N (real code transforms)📝 Annotated: N (advisory comment only — still needs manual fix)⏭ Skipped: Ngrep -rn KCODE-AUDIThint so users can find their open TODOs.Workflow orchestrator —
src/core/task-orchestrator/workflow-chain.tsfixes_appliednow counts onlytransformedentries. Annotations no longer inflate the success number.Security fixes from KCode's own self-audit
src/core/mcp.ts:McpManager.loadFromConfigsrejects__proto__/constructor/prototypeas MCP server names and usesObject.create(null)as the accumulator.src/tools/notebook-utils.ts:parseNotebookwrapsJSON.parsein try/catch, re-raises asInvalid notebook JSON: …, and rejects non-object roots.Pattern library —
src/core/audit-engine/patterns.tssh-001-eval-injectionmoved from[c,cpp,python,js,ts,go,rust,java]to[shell](new language in the Language union).py-020-global-keywordverify_prompt expanded to list 9 idiomatic module-level-state patterns the verifier should mark FALSE_POSITIVE (circuit breakers, rate limiters, connection pools, memoization caches, etc.).Verified against SmartSolar
A /fix run on SmartSolar with the new pipeline:
as T→as T? ?? defaulttransforms (real code change).📝 annotatedbecausedart-006-future-no-errorstill routes through the generic recipe.Tests
json[...]casts, leaves non-JSON casts alone.State<T>.annotated, nottransformed.applyRecipeno-duplicate guarantee across three /fix runs.Test plan
bun test src/core/audit-engine/— should report 34 pass.bun test src/core/mcp-proto-pollution.test.ts src/tools/notebook-utils.test.ts— should report all green.bun run build— should produce a workingdist/kcodebinary.kcode --version— should report2.10.13./scan .and/fixagainst any project with.plugin_symlinks/,Pods/, or.dart_tool/in its tree and verify no findings come out of those directories./fixoutput shows three buckets (✅ Fixed/📝 Annotated/⏭ Skipped) not a singleAppliedcount.🤖 Generated with Claude Code