mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 08:15:53 +00:00
Squash-merge of feat/autofix-pr-test (69 commits) onto upstream/main with -X ours strategy (upstream as authoritative for content conflicts). Key features brought in from fork: - LocalMemoryRecall + VaultHttpFetch tools (end-to-end wired) - /local-memory, /local-vault, /memory-stores, /skill-store interactive panels - /agents-platform, /schedule, /vault command scaffolding - /login: switch / replace / remove of workspace API key - statusline refactor (built-in status row, /statusline as info command) - autofix-pr command + workflow Conflict resolutions (upstream-wins): - 10 .js command stubs kept from upstream (alongside fork's .ts implementations) - src/components/BuiltinStatusLine.tsx accepted upstream's deletion (fork's wire-up references in StatusLine.tsx will be cleaned up next) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
9.0 KiB
9.0 KiB
Cross-Audit 2026-04-29 — Stub Recovery Bugs
Scope: ~3.8k lines across 10 commands + claude.ts break-cache integration. Read-only audit.
A. Silent failures
- HIGH
src/commands/break-cache/index.ts:60-62—readStatsswallows ALL errors (parse error, EACCES, EISDIR) and returns defaults. A corrupt stats file silently maskstotalBreaks. Fix: log the error path, or rename file with.corrupt-<ts>suffix on JSON.parse failure. - MEDIUM
src/commands/share/index.ts:113-121, 117—buildSummaryContentouter try/catch returns''on read failure; caller treats''as "no content found" and emits a misleading message. Fix: throw to let the caller surface the real error. - MEDIUM
src/commands/issue/index.ts:96-98, 121-123—repoHasIssuesEnabledanddetectIssueTemplatereturnnullon any error including auth/network; user sees no signal that issue-template detection failed. - LOW
src/commands/perf-issue/index.ts:386-391—analyzed = nullon parse error → silently produces an all-zero report indistinguishable from a fresh session. Fix: include aparse_errornote in the report. - LOW
src/services/api/claude.ts:1462-1466—unlinkSynconce-markercatch {}is intentional; safe but should log viadebug.
B. Resource leaks
- MEDIUM
src/commands/autofix-pr/launchAutofixPr.ts:255-263— On teleport throw,clearActiveMonitor(taskId)is called which DOES abort the controller — OK. But ifregisterRemoteAgentTaskthrows (line 289), the remote CCR session is already created with no abort path; only local lock is released. Document or surface a "remote session orphaned, cancel from claude.ai" hint. - LOW
src/commands/autofix-pr/monitorState.ts:42-47—clearActiveMonitoraborts the controller but never removes any registered listeners on the signal. Acceptable for a singleton with process-lifetime scope. - PASS —
share/index.tsmkdtempSynccleanup usesfinallyblock; correct.
C. Concurrency / race
- HIGH
src/commands/break-cache/index.ts:71-78, 169, 190—incrementBreakCountand writes tobreak-cache-stats.json/.break-cache-alwaysare NOT atomic. Two concurrent/break-cache onceinvocations lose one increment (read-modify-write race) and may also race with the unlinkSync in claude.ts:1463. Fix: write to a temp file then rename, or accept the race and document. - PASS
monitorState.ts:21-25—trySetActiveMonitoris atomic in single-threaded JS event loop. Comment in launchAutofixPr.ts:166-169 correctly notes the await-free synchronous CAS. - MEDIUM
agents-platform/agentsApi.ts:102-121—withRetryretries on 5xx but does NOT honorRetry-Afterheaders; under sustained 5xx storm three concurrentlistAgentscalls will all hammer at exponential 0.5/1/2s.
D. Input validation / overflow
- HIGH
src/commands/ctx_viz/index.ts:362-367—--max-tokens=Naccepts any positive int; passing--max-tokens=999999999999producesslotSize ≈ 2e7andMath.round(cacheRead/slotSize)underflows to 0; harmless butBAR_WIDTHmath inrenderPerTurnBreakdown(line 321Math.max(1, Math.round(...))) emits at least 1 cell of color even for zero-token turns — misleading. Cap at e.g.1e9. - MEDIUM
src/commands/perf-issue/index.ts:97—readFileSync(logPath, 'utf8')reads the entire JSONL into memory; for long-running sessions transcripts can reach hundreds of MB → OOM risk. Same pattern inshare/index.ts:88,issue/index.ts:143,ctx_viz/index.ts:226,debug-tool-call/index.ts:88. Fix: stream line-by-line viareadline. - MEDIUM
src/commands/agents-platform/parseArgs.ts:29—tokens.length < 6requires at least 1 prompt token, but a multi-line prompt with quoted whitespace gets shredded (single-quote/double-quote not respected). Cron"0 9 * * 1"arg is split on spaces, producing 5 cron + N prompt tokens — user must NOT quote. Document or implement shell-style quoting. - LOW
src/commands/issue/index.ts:56-62— owner/repo regex[\w.-]+admits leading./..; combined with the URL fallback at line 354 produceshttps://github.com/.../...issues/new. Browsers tolerate it but a malformed remote URL leaks into the analytics event at line 441. - LOW
src/commands/share/index.ts:166-167—if (!url.startsWith('https://'))rejects only obvious failures; a gh subprocess that printshttps://attacker.example.com\nhttps://gist.github.com/...would pass sinceresult.stdout.trim()keeps multi-line. Use.split('\n')[0].trim().
E. Path traversal / security
- MEDIUM
src/commands/perf-issue/index.ts:379—${sessionId.slice(0, 8)}is interpolated into the report filename; if a malicious session id contained../,mkdirSync({recursive:true})would happily traverse. Mitigated bygetSessionId()returning a trusted UUID, but defensive:sanitizePath(sessionId.slice(0,8)). - MEDIUM
src/commands/share/index.ts:179—curl -F 'file=@${filePath}':filePathismkdtempSyncoutput so trusted; OK for now. - MEDIUM
src/commands/share/index.ts:42-69— Secret-mask regex\b(sk-[A-Za-z0-9]{20,})is greedy and may mask non-secret strings (any base64 token starting withsk-). And the[0-9a-f]{32,64}MD5/SHA pattern (line 65) will mask legitimate git SHAs in the conversation, garbling the share. Acceptable trade-off but document. - HIGH
src/commands/issue/index.ts:343-376— Whenghis missing,bodyfrom session transcript is URL-encoded into a browser link withencodeURIComponent. Browsers cap URL length ~8000 chars;getTranscriptSummary(5)slices to 200 chars per turn × 10 entries + errors — fits, but no hard cap. Fix: clamp body to ~3000 chars before encode. - MEDIUM
src/commands/env/index.ts:34-46—KAIROSallowlist (no underscore) matches any env var starting withKAIROS(e.g.,KAIROSE_INTERNAL_TOKEN). Should beKAIROS_. - MEDIUM
src/commands/env/index.ts:25-32—maskValueshows first 4 chars of secrets ≥ 9 chars;sk-ant-…prefix leak (4 chars) is borderline. Acceptable; but<= 8falls back to***which is fine.
F. Error matrix
- MEDIUM
src/commands/teleport/launchTeleport.ts:133-162— Three error branches (forbidden|401|403,not found|404,token|unauthorized) overlap. A 403 response with body"unauthorized token"would match theforbiddenbranch first (correct) but tests don't cover the priority. Document priority. - LOW
src/commands/agents-platform/agentsApi.ts:85-88— 403 message hardcodes "Pro/Max/Team" — diverges from upstream subscription tiers; LOW since string. - PASS —
autofix-prcoverssession_create_failed,repo_mismatch,teleport_failed,registration_failed,rc_already_monitoring_other,exception— comprehensive. - MEDIUM
src/commands/issue/index.ts:459-477—gh issue createfailure surfaces full stderr to user; if gh embeds the title (which can contain user-supplied content) into error message, no info leak per se butmsg.slice(0, 200)is logged to analytics — confirm analytics field is not PII-tagged.
G. Production risk
- HIGH
src/commands/perf-issue/index.ts:13-19—COST_RATEShardcoded to Claude 3.7 Sonnet rates. As of 2026-04-29 with Sonnet 4.6 and Opus 4.5 in use, the cost estimate is wrong. Fix: read from a constants file or remove cost estimate altogether. - HIGH
src/commands/perf-issue/index.ts:128-148— Tool durations useDate.now()AT PARSE TIME (when /perf-issue is run), not log timestamp. Every tool will havedurationMs ≈ same value(the time between consecutive parse iterations, microseconds). The output is meaningless. Fix: readentry.timestampfor both tool_use and tool_result and subtract; or remove the tool-duration table. - MEDIUM
src/services/api/claude.ts:1455+break-cache/index.ts— Nonce israndomUUID()(128 bits crypto-random), correctly cache-busts since the<!-- cache-break nonce: X -->line forces prefix-hash differ. PASS. - MEDIUM
src/commands/agents-platform/agentsApi.ts:141— Hardcodedtimezone: 'UTC'despiteAgentTrigger.timezonebeing a field. User cron expressions interpreted in UTC regardless of locale → silent surprise for users in non-UTC TZ. Fix: accept--tzflag or useIntl.DateTimeFormat().resolvedOptions().timeZone. - MEDIUM
src/commands/perf-issue/index.ts:374— Filename usesnew Date().toISOString().replace(/[:.]/g,'-')— UTC-based, but local users may expect local time. Document or use local TZ. - LOW
src/commands/share/index.ts:340—mkdtempSync(join(tmpdir(), 'cc-share-'))plus immediate write toclaude-session.jsonl: tmp file may persist if process is SIGKILLed mid-upload (rmSync in finally won't run). Acceptable for share; note it.
OVERALL-VERDICT: NEEDS_FIX
- CRITICAL: 0
- HIGH: 5 (break-cache atomicity, ctx_viz max-tokens, issue body cap, perf cost rates stale, perf tool durations meaningless)
- MEDIUM: 13
- LOW: 5
Top three to fix before merge: (1) perf-issue tool-duration timestamps (G), (2) break-cache stats RMW atomicity (C), (3) issue browser-fallback body length cap (E).