sm4c is a local TUI that hosts the Claude Code CLI inside an isolated tmux server. This file documents the threat model, the secure-coding practices enforced in the codebase and CI, and how to report security issues.
Please do not open public GitHub issues for suspected security problems. A public issue can tip off attackers before a fix is available.
Report privately via either of these channels:
- Email dev@lilfrogdev.com (preferred).
- Use GitHub's private vulnerability reporting flow ("Report a vulnerability" under this repository's Security tab).
We aim to acknowledge reports within 5 business days and to provide a remediation or status update within 30 days. Please include:
- sm4c version (
sm4c version) - tmux version (
tmux -V) - OS and architecture
- Steps to reproduce, expected vs. observed behavior
- Any logs, with sensitive content redacted
During v0 / pre-alpha, only the latest commit on main is supported. Starting with v1.0 we will document supported release branches here.
In scope:
- The
sm4cbinary (TUI and CLI). - Everything under
cmd/andinternal/. - The CI supply chain (GitHub Actions workflows, Makefile, dependency manifests).
- Documented config file formats.
Out of scope:
- Vulnerabilities in
tmux,claude,go, or third-party dependencies themselves. Report those upstream. sm4c will bump once a fix is available. - Local-user-to-local-user attacks where the attacker already has the same UID as the victim. sm4c assumes the local UID is the trust boundary; it does not defend against an adversary who already owns your account.
- Terminal emulator bugs. sm4c sanitizes outgoing output to mitigate terminal escape-sequence attacks, but we can't fix a broken terminal.
sm4c's attack surface is shaped by the fact that it proxies a third-party process (claude) whose output can be indirectly influenced by remote content (user prompts, web search results, tool output). We treat everything coming from claude as untrusted input.
Primary threats we explicitly defend against:
- Outer-terminal escape-sequence injection. A hostile
claudeoutput (e.g. reflected from a poisoned tool result) could try to emitESC]/ESC[sequences that change the user's outer terminal state (clipboard, title, cursor,DECSETmodes). sm4c rendersclaudeoutput through a VT emulator and only forwards a whitelisted subset of escapes to the outer terminal. - Command injection into
tmux/claude. Session names, window names, user-provided args, and config values are the primary injection vectors. sm4c never usessh -c; every subprocess is built withexec.Command(bin, args...)where each argument is its own slice element. All strings bound fortmuxarguments pass throughinternal/safe. - Path hijacking / TOCTOU on binaries.
tmuxandclaudeare resolved viaexec.LookPathonce at startup, the resolved absolute path is recorded, and subsequent invocations use that absolute path.PATHis not re-consulted per-call. - Socket squatting. sm4c's tmux socket lives under a per-user directory whose path and mode are validated at startup (owner = current UID, mode
0700). sm4c refuses to start if the socket directory is world- or group-writable, or owned by another user. - Keystroke cross-routing. Keys intended for one
claudesession must never reach another. sm4c binds everysend-keyscall to an explicit{sessionID, windowID}target captured from a verified%window-addevent; stale targets are rejected. - Sensitive data leakage via logs. At default log level (
INFO) sm4c never writes keystrokes, session content, or model output to disk.--debugraises the level and prints a conspicuous warning; even at--debugwe redact common secret patterns before logging. - Supply-chain risks. Dependencies are minimized, pinned via
go.sum, scanned bygovulncheckin CI, and built with-trimpath -buildvcs=truefor reproducibility.
The following rules are enforced by CI and/or golangci-lint:
- No shell interpolation.
os/execwithsh -c/bash -cis banned. A repo grep in CI flags any new occurrence. - No network. sm4c must not import
net/http,net/smtp,net/rpc, callnet.Dial*, or open listeners. A repo grep in CI flags imports outside the allowlist. - No hex colors. Terminal-native theming is mandatory;
lipgloss.Color("#...")is banned via a repo grep. go vet,staticcheck,golangci-lint(withgosec) must pass with zero findings.govulncheckmust pass with zero findings onmain.- Reproducible builds. Release builds use
go build -trimpath -buildvcs=true -ldflags='-s -w'. - No
init()side effects outside of cobra subcommand registration. internal/safeis the single entry point for user-controlled strings crossing into tmux args or terminal output. Unit tests cover escape injection, BIDI overrides, C0/C1 controls, and length limits.
- sm4c does not read, store, forward, or log your Anthropic API key. The key is handled entirely by
claude. - sm4c does not auto-update, phone home, or emit telemetry.
- sm4c does not persist any session transcripts. Scrollback lives in tmux's memory and is scrubbed on session close.
- sm4c does not accept input on any network socket.
sm4c does not generate, store, or rotate cryptographic keys. Session identifiers are tmux-assigned and treated as opaque.