Security model and limits
Secret is accident prevention for coding agents. It is not a sandbox and does not contain an agent that is deliberately trying to read a secret.
It keeps credential values out of an agent's context when the agent reaches for them by habit or mistake: cat .env, printenv, gh auth token, a content search over a directory holding a store. The CLI, guard and agent skill can be used together or separately; guidance is not enforcement. The full threat model is in SECURITY.md.
What it protects
- Store values never pass through the CLI's own argv or diagnostics.
showandlistprint names, masked lengths and paths only.rundelivers selected keys through the child's environment and replaces every loaded value with<redacted>on stdout and stderr. If a redaction filter fails,runstops the child and exits 1 rather than printing unfiltered output. - Writes are private and atomic.
stashreads values from a hidden prompt or stdin, writes the replacement inside a private 0700 directory and renames it onto the store under a lock. It refuses symlinked and non-regular targets. File stores are parsed asKEY=VALUEdata, never sourced as shell code. - The guard denies the common accidents before a tool call runs: reading store files and well-known credential files (cloud CLI credentials, Docker and gh config, npmrc, pypirc, SSH private keys,
/proc/*/environ), dumping the environment, credential printers such asgh auth token,gcloud auth print-access-token,op read,secret-toolandsecurity -w, clipboard readers, and content searches over trees that hold protected files. The checks inspect syntax and path metadata; they never execute the command. - Malformed requests deny. A nonempty malformed request or failed static analysis denies instead of allowing the tool call, and over-budget commands deny rather than being allowed. Split long commands into smaller calls.
The Bash guard requires jq and denies every request when jq is unavailable.
Names-only MCP boundaries
MCP is opt-in local stdio with explicit exact --store references, not a network service or credential transport. Its four tools never return values, value hashes or lengths and expose no mutation, resource or prompt capability.
Names-only metadata can still disclose key names, labels, presence, backend, references and paths, and provider account IDs to clients, models and logs. File metadata parsing may open local file bytes internally; provider metadata never calls value Get. Age outer metadata is unauthenticated. Health proves only configured readiness and store count. MCP registration grants no guard exception.
Installer trust
The pinned HTTPS one-liners execute a script before payload verification and trust GitHub HTTPS, repository ownership and tag governance and the reviewed installer. They resolve latest once (or use an explicit version), then verify HTTPS checksums, executable format and architecture and bounded new-binary version output. This detects corruption, not a compromised release publisher. There is no automatic attestation check; manual provenance and the stronger authenticated checkout route remain available. Installed executables are hashed, never executed, when deciding whether to replace them.
What it does not protect
These are outside the threat model. Reports about them are welcome as documentation or hardening suggestions, but they are not vulnerabilities.
- Transformed output. Redaction matches literal values. Base64, URL encoding, hex, substrings, reversed or split values are not caught.
- Shell indirection the guard cannot resolve statically. The guard tokenizes commands and never evaluates them. Variables set elsewhere, files of commands,
eval, aliases, functions and interpreters reading paths from their input can name a protected file without spelling it. - Deliberate shell and repository construction. Scripts or build files written and run in one command, and hand-built Git directories, are not tracked across command boundaries.
- Tools the guard does not see. The hook covers Claude Code's Bash, Read, Grep, Edit, Write, MultiEdit and NotebookEdit tools, and Codex's Bash shell hook and
apply_patch. Hosted tools such as web search, MCP servers, other agents and other editors are not covered. - Process-level visibility. A child that puts a value in its own argv exposes it to the local process list. Any process running as the same user can read the stores and, while a child runs, its environment.
- What env-file consumers do with values.
docker run --env-file .envand similar consumers are allowed; an arbitrary program given those values can still print them. - Executable substitution. The guard trusts command names. A different program named
secret,catorjqearlier on PATH is not detected. - Clipboard consent.
secret clipis allowed for agents because the value never reaches their output; the skill limits it to explicit user requests, which a hook cannot verify. - Searches without the protective ripgrep config. Plain
rgis treated as safe only when the effective ripgrep config excludes store files; otherwise content searches over trees holding protected files are denied.
A disabled or missing host hook cannot enforce any decision. Go hooks remain inactive, and installing an executable, registering MCP or passing synthetic tests does not establish fail-closed host protection.
Reporting
Use GitHub's private vulnerability reporting for anything that lets a value reach agent output through a path the guard or the CLI claims to cover. Describe the command or tool call and the observed decision. Never include a real credential; synthetic values like synthetic-token reproduce every case the test suites cover.
Frequently asked questions
What is Secret?
Secret is a GPL-3.0-or-later licensed Go tool for coding agents: a local credential CLI, a names-only MCP server and a guard hook. The agent chooses keys by name; secret run passes selected values to the child process through its environment and redacts loaded literal values from its output. Transformed output and arbitrary child behavior are not covered. It runs on Linux, macOS and Windows.
Can an agent read my values through the MCP server?
No. The four tools list, show, diff and health never return values, value hashes or lengths. Names-only is not metadata-private; see the MCP boundaries.
Who enters the values?
You do, in your own terminal. secret stash reads a value from a hidden prompt and writes it atomically. secret get prints a value only to a human terminal and the guard denies it to agents.
Does secret run catch every leak in output?
No. Redaction matches literal values only; see transformed output and process-level visibility under what it does not protect.
Is the guard hook a sandbox?
No. The guard is accident prevention: it denies known secret-reading operations before a tool call runs, but it cannot contain a determined agent, transformed values, arbitrary child behavior or tools it never sees. Installation and synthetic tests do not prove host fail-closed protection.
Which agent tools does the guard see?
Claude Code's Bash, Read, Grep, Edit, Write, MultiEdit and NotebookEdit tools, and Codex's Bash shell hook and apply_patch. Hosted tools such as web search, MCP servers, other agents and other editors are not covered. Codex requires explicit hook trust in /hooks, including re-trust after changes.
Can I give secret exec to an agent?
No. exec is run without redaction, for human interactive tools and configured MCP server launchers that need byte-exact stdio. Its output is unfiltered and can disclose values, and the guard denies it to agents.
Does registering the MCP server change what the guard allows?
No. MCP registration grants no guard exception and does not install or activate hooks. The installed hooks conservatively deny new subcommands to agents, including names-only ones.
How far can I trust the one-line installers?
They trust GitHub HTTPS, repository and tag governance and the script before payload verification; HTTPS checksums detect corruption, not a compromised release publisher. See installer trust.
What differs on Windows?
Windows supports file stores and wincred stores backed by Credential Manager, with protected owner-only DACLs and native Job containment for run and exec children. Windows age, pass and 1Password remain unsupported, and redaction covers UTF-8 plus UTF-16LE and UTF-16BE, not other code pages. No installed-hook or fail-closed PowerShell or CMD host protection is claimed.
How do I report a vulnerability?
Use GitHub's private vulnerability reporting on the repository for anything that lets a value reach agent output through a path the guard or the CLI claims to cover. Never include a real credential; see reporting.