Skip to content

Harden IPC security, async transcription, model label display#35

Merged
lcoutodemos merged 1 commit intomainfrom
develop
Mar 20, 2026
Merged

Harden IPC security, async transcription, model label display#35
lcoutodemos merged 1 commit intomainfrom
develop

Conversation

@lcoutodemos
Copy link
Copy Markdown
Owner

Summary

  • Security hardening across 5 IPC boundaries (from PR Security hardening, TS fixes, JS drag, and dynamic window resize #12 analysis — took what was right, rejected what would break reliability):

    • OPEN_IN_TERMINAL: UUID-validate sessionId, single-quote shell escaping to block $() and backtick injection via projectPath
    • LOAD_SESSION: UUID-gate sessionId to prevent path traversal (../../etc/passwd.jsonl)
    • LIST_SESSIONS / LOAD_SESSION: reject null bytes, newlines, non-absolute projectPath
    • OPEN_EXTERNAL: replace regex with new URL() constructor for protocol/hostname validation
    • Marketplace install/uninstall: validate pluginName charset, repo owner/repo format, sourcePath traversal, and resolve() containment check ensuring paths stay under ~/.claude/skills/
  • Async transcription — replaced execSync with async execFile wrapper so voice transcription no longer blocks the Electron main thread (fixes macOS loading cursor / app freeze during recording)

  • Transcription diagnostics — per-phase timing logs (decode+write_wav, probe_binary_paths, whisperkit_transcribe_report, etc.) written to ~/.clui-debug.log on every transcription

  • Conditional fallback — WhisperKit only re-runs transcription if first run produced empty stdout (was unconditional before, causing ~2x latency)

  • Model label display — normalizes model IDs with context window hints (e.g. claude-opus-4-6[1m]Opus 4.6 (1M)) for the status bar picker

Test plan

  • npm run build compiles clean
  • Voice transcription works (no app freeze / loading cursor)
  • tail -f ~/.clui-debug.log shows timing breakdown per transcription
  • Model picker displays correct labels for all model variants
  • "Open in Terminal" works with normal project paths
  • Marketplace install/uninstall works for valid plugin names

Security vectors verified

Attack Handler Result
sessionId = '$(curl evil)' OPEN_IN_TERMINAL Rejected (UUID check)
projectPath = '/tmp/$(touch pwned)' OPEN_IN_TERMINAL Safe (single-quoted)
sessionId = '../../etc/passwd' LOAD_SESSION Rejected (UUID check)
pluginName = '../../../tmp/evil' installPlugin Rejected (charset + containment)
url = 'javascript:alert(1)' OPEN_EXTERNAL Rejected (URL constructor)

…play

Security (from PR #12 analysis):
- OPEN_IN_TERMINAL: UUID-validate sessionId, reject malicious projectPath,
  use single-quoted shell escaping to block $() and backtick injection
- LOAD_SESSION: UUID-gate sessionId to prevent path traversal
- LIST_SESSIONS/LOAD_SESSION: reject null bytes, newlines, non-absolute projectPath
- OPEN_EXTERNAL: replace regex with URL constructor for protocol/hostname validation
- Marketplace install/uninstall: validate pluginName charset, repo format,
  sourcePath traversal, and enforce resolved path stays under ~/.claude/skills/

Performance:
- Replace execSync with async execFile in transcription to stop blocking
  the Electron main thread (eliminates macOS loading cursor during voice input)
- Add per-phase timing logs for transcription diagnostics
- Conditional fallback re-run: only re-transcribe if first run produced no stdout

UI:
- Normalize model IDs with context window hints (e.g. "[1m]") for display
- Add getModelDisplayLabel helper for future-proof model name rendering
@lcoutodemos lcoutodemos merged commit 79adb7a into main Mar 20, 2026
@lcoutodemos lcoutodemos deleted the develop branch March 20, 2026 22:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant