| Version | Supported |
|---|---|
| 0.1.x | ✅ |
Security fixes are applied to main and the latest 0.1.x release. Pin to a tagged release and run pnpm audit locally before deploying.
Do not open a public issue for security vulnerabilities.
- Use GitHub Security Advisories: go to the repository Security tab > Report a vulnerability (private disclosure).
- Alternatively, email the maintainer listed in
package.json/ GitHub profile with subject[SECURITY] coxswain. - Include: affected version/commit, reproduction steps, impact, and any PoC (redact secrets).
What to expect:
- Acknowledgment within 3 business days.
- Triage and initial assessment within 7 business days.
- Fix and coordinated disclosure window communicated once triage is complete.
- Credit offered if desired once the fix is released.
Please avoid automated bulk scanning that triggers abuse detection and do not exfiltrate data beyond what is needed to demonstrate impact.
Coxswain (cox) is a local-first CLI and agent orchestrator. It intentionally spawns shell commands and long-lived daemons on the developer's machine and in CI. The primary trust boundary is the local workspace and the user who invoked cox. Remote code (model outputs, MCP tool results, fleet peers) is untrusted input that must not gain host capabilities outside the declared tool contracts.
Surface: The agent bash tool executes arbitrary shell commands via child_process.spawn / exec on the host. There is no container or seccomp sandbox by default; commands inherit the user's UID, env, filesystem, and network.
Threats:
- Prompt injection or poisoned tool output causes the model to emit a destructive command (e.g.,
rm -rf, credential exfiltration viacurl, supply-chain install). - Workspace path traversal (e.g.,
../../) or env expansion ($HOME,$AWS_*) escapes the intended project root. - Long-running or forking commands outlive the agent turn and leave orphaned processes.
Mitigations in place / required:
- Treat every bash invocation as privileged. Require explicit user approval when an agent session would run shell commands outside the workspace root or with network access, where the host supports an approval gate.
- Default to allowlisting: prefer project-scoped commands (
pnpm,git,node scripts/*) and validateworkdiris inside$WORKSPACE_ROOTbefore spawn. - Enforce timeouts and
max_output_tokens/ output truncation so unbounded output cannot fill disk or OOM the controller. - Log every spawn (command, workdir, exit code, truncated output) to
.cox/sessions/for audit. - In CI, run with
concurrencycancellation,timeout-minutes, and least-privilegeGITHUB_TOKENpermissions.
Contributor guidance: Any new code that adds a bash call must document the exact command shape, validate workdir, and add a test that asserts traversal is rejected.
Surface: Lifecycle hooks (.cox/hooks/*, scripts/*, Husky pre-commit, and .pre-commit-config.yaml hooks) execute shell code automatically on git commit, cx run, or daemon start. Hooks run with the same privileges as the user.
Threats:
- A malicious or compromised hook script persists across clones and executes on every commit or run (supply-chain persistence).
- Hook scripts that
evaluntrusted config (e.g.,board-sync.json, journey YAML) lead to code execution. - Secrets printed by hooks leak into logs or artifacts.
Mitigations in place / required:
- Hooks are not auto-installed on clone.
cx initcopies hook templates explicitly andgit config core.hooksPathis opt-in. - All shipped hooks are checked into version control and reviewed; local overrides in
.cox/are gitignored and must be inspected before enabling. - Hooks must be idempotent, non-networked, and must not
evalworkspace data. Parse JSON/YAML with a safe parser, neverbash -c "$(cat file)". gitleakspre-commit (see.pre-commit-config.yaml) blocks accidental secret commits before hooks push.- CI never executes local hooks (
--no-verifyequivalent for automated commits) and runs hooks inbash -euo pipefailmode so failures are visible.
Contributor guidance: Adding a hook requires updating this file and docs/ with the hook's purpose, trigger, and privilege level. Never add a hook that fetches remote code at runtime.
Surface: cx daemons write daemon.pid, daemon.json, and daemon.log under .cox/cx/<stack>/ (gitignored). The controller reads daemon.pid to decide if a daemon is live, to send signals, or to reuse a port.
Threats:
- TOCTOU race: PID file is read after an attacker or stale process replaces it, causing a signal to be sent to the wrong PID (PID reuse / symlink attack).
- Two concurrent
cx stack-upinvocations both see no PID file, both write, and one daemon is orphaned while the other is killed. - Stale
daemon.pidafter unclean exit causes denial of service (controller refuses to start a new daemon).
Mitigations in place / required:
- Daemon start uses atomic write +
O_EXCL+fsyncfor the PID file and records{ pid, startTime, nonce }indaemon.json. Liveness is verified bypid + startTime(viaprocessstart time //procon Linux,ps -o lstarton macOS), not PID alone. - PID file is created with
0600permissions and lives under.cox/cx/<stack>/which is gitignored and not world-writable. Symlink following is rejected (lstatcheck). - Lock file (
.cox/cx/<stack>/.lock) is held withflock/ file-lock during start/stop so concurrent invocations serialize. - Shutdown removes
daemon.pidonly if the stored nonce matches the current daemon; stale files are detected by failed liveness probe and reaped after a grace period. - CI and local
cx doctorverify no orphaned daemons and clean stale PID files before starting.
Contributor guidance: Do not change daemon lifecycle code without preserving the atomic-write, liveness-by-startTime, and lock-file invariants. Add a regression test that simulates concurrent start and PID reuse.
- Secrets:
.envand.env.localare gitignored. Usegitleakspre-commit andpnpm auditin CI; never commit tokens. Rotate any accidentally committed secret immediately. - Dependencies: Dependabot (pnpm + github-actions, monthly) and
pnpm audit(CI,continue-on-error) surface known CVEs. Pin GitHub Actions to commit SHAs where feasible. - Supply chain:
pnpm-lock.yamlis committed;pnpm install --frozen-lockfileis enforced in CI. VerifypackageManagerfield. - OSSF Scorecard:
.github/workflows/scorecard.ymlruns weekly and publishes results to the Security tab.
- No new unsandboxed
spawnwithout workdir validation and timeout. - No new hook that executes untrusted workspace content.
- No PID file handling without atomic write and startTime verification.
-
pnpm auditpasses or new advisories are triaged. -
gitleakspre-commit passes locally (pre-commit run --all-files).
Thanks to reporters who follow coordinated disclosure. Contributors who improve the threat model or mitigations above will be credited in release notes unless they prefer anonymity.