Security model
What protects what in enveigh: at rest, in transit to your tools, and against a misbehaving agent.
enveigh lets tools use secrets without seeing them, and it records every access. This page says how, and where the limits are.
At rest
- Values live in the macOS Keychain, keyed by an immutable
(secret id, version). Rotating a key writes a new entry and never changes an old one. - Metadata (names, tags, version history, never values) is stored in app data, encrypted at rest with AES-GCM under a key held in the Keychain. enveigh moves any older plaintext store to this format on launch.
- Vault files are owner-only (
0600files,0700directory). - Manual backup (Settings > Backup): export a file protected by a passphrase, a generated recovery key (either one opens it), or, if you choose, no encryption. Restore on another Mac from setup or from the same pane. You review the date and counts first, and Undo last restore brings back the vault that was active before. enveigh makes no scheduled or automatic exports, so a backup exists only when you make one.
The lock
Secrets flow only while the app is running and unlocked (Touch ID or your password). When you lock or quit the app, the broker stops, the endpoint is cleared, and enveigh drops any revealed plaintext from memory. No background daemon holds keys open.
The broker (how tools reach values)
The unlocked app exposes a local UNIX-domain socket (0600, owner-only) plus a token.
The broker gates every request:
- Token and scope. The CLI uses the full session token. Each MCP client gets its own scoped, revocable token. The broker compares tokens in constant time.
- Real caller identity. The broker reads the connecting process's PID from the kernel
and walks its parent chain (
enveigh ← node ← Claude). The broker derives the requestor shown in the prompt and the audit log, so a caller cannot claim to be another process. - Approval policy (your choice in Settings > General > Agent approval):
- Touch ID per request: the strongest.
- Touch ID once per environment: the default. You approve once per session.
- Unlocked = allowed: no prompt while unlocked. See the limits below.
- Sealed policy. enveigh stores the approval policy inside the vault, sealed under the vault key. Another program running as you can delete it but cannot write one that enveigh accepts. If the policy is missing or damaged, enveigh asks on every request. Choosing a policy that asks less often needs Touch ID or your Mac password. Since 0.2.11, anyone who chose Unlocked = allowed is on Touch ID once per environment until they choose it again.
- Trusted session (for long unattended agent runs): start it from the menu-bar icon and confirm once with Touch ID. The broker then serves agent requests without prompting until your presence can no longer be assumed. That ends on screen lock, screensaver, sleep, fast user switch, or when you lock the vault. A trusted session is never a saved setting and does not survive a relaunch. enveigh still audits and notifies every access. Deleting an environment always prompts.
- Audited before disclosure. enveigh writes reveal, render, capture, and agent access to the audit log before it releases the value. If the audit write fails, enveigh returns no value.
Against a misbehaving agent
- The default agent tool,
run_with_env, redacts every injected value from the output the model reads, and caps output size. - Raw-value tools (
render_env,get_secret) are not even exposed unless you opted that client into reveal, and then they're still Touch-ID gated and audited. They also carry theanthropic/requiresUserInteractionannotation, so Claude Code prompts for them in every permission mode, even when you've pre-approved the rest of the server. - Pre-approval is scoped to the server, never to values. The optional "Pre-approve enveigh tools" setting silences only the client's prompt for tools that the app already confirms with Touch ID. It writes an allow rule in Claude Code, an approval mode in Codex, or a trust flag in Gemini CLI, and disconnecting removes it. See Client permission prompts.
capture_secretis write-only: an agent can store a key but can never read one back.- enveigh scrubs inherited credential-shaped environment variables from agent-run child
processes, so a secret exported in the shell that launched the helper cannot leak to the
agent.
SSH_AUTH_SOCKis kept. It is the ssh-agent's socket path, not a credential. - enveigh ends
run_with_envchildren at a timeout (default 10 minutes), so a hung command cannot hold an injected environment open.
Catching keys before they spread
Two layers, by timing:
- Clipboard watcher (opt-in, Settings > Security). When you copy something credential-shaped, enveigh offers to vault it before you paste it anywhere. Detection is local. enveigh ignores other clipboard content and never stores or sends it. It skips enveigh's own copies and ordinary developer text such as git SHAs, UUIDs, and URLs.
capture_secretand the skill. If a key does reach an agent, the agent offers to vault it (you confirm) and stops using the pasted copy.
Honest edges
Know these limits:
run_with_envredaction is exact-match. A deliberately hostile agent could encode a value with base64 or another transform before it prints the value, and so avoid redaction. The default protects against casual exposure. It does not stop an actively malicious agent that runs arbitrary commands with the environment injected.- The CLI is your tool: full access, live output. An agent with shell access and
enveighonPATHhas more reach than the scoped MCP server. The approval policy is the gate. Unlocked = allowed removes it, so it is not the default. - Same-user programs can read tokens at rest. The broker is a same-user trust boundary. The approval policy, not file secrecy, is the real control. With the default policy, a prompt names the real caller.
Not the Mac App Store, on purpose
The App Store sandbox would break the Keychain and broker model that enveigh needs. enveigh ships as a Developer ID-signed, notarized direct download with a built-in updater.
On Linux
The Linux terminal edition stores values with your GPG key in a dedicated pass store
instead of the Keychain. Approvals happen in the TUI instead of with Touch ID. Unlocking
through pinentry follows GPG's cache policy, which is not a fresh biometric check. The
service seals the approval policy with your GPG key and ignores any copy in settings.json.
Approving a request needs proof that you are present: you unlock in the TUI first. The
signed pacman repository uses the key 0CC6 120F 14A3 DE01 4FC8 C3AD 7B34 D87A 7988 4ACB.
See Linux > Security model.