cubby exists to keep secrets out of an AI agent's context. It is important to be
precise about what that does and does not buy you.
- Secrets in an agent's context/transcript. The agent runs
cubby run -- <cmd>;cubbyinjects secret values into the child process's environment and never prints them. The agent sees the command's output, not the secret.cubby getshows only metadata unless--revealis passed. - Plaintext secrets at rest. Each namespace is stored as an
age-encrypted file. Nothing is written to disk in cleartext. - Secrets in shell history / process arguments.
cubby setreads the value from a hidden prompt (or stdin), never fromargv. - Wrong-namespace leakage. Namespace resolution matches working-directory prefixes
on path boundaries, so
/p/projectis never treated as part of/p/proj. - A record of secret access. With the opt-in audit log enabled
(
cubby audit --enable), everycubby run,cubby get --reveal, andcubby get --copyappends a timestamped line to~/.config/cubby/audit.log. The log records the event, namespace, and command — never a secret value. The log self-rotates at ~1 MB (current log moves toaudit.log.1, a fresh one is started), so it never grows without bound;cubby audit --allshows both files.
- A compromised machine or a malicious local user with your privileges. Anyone who
can read the age identity (
~/.config/cubby/identity, mode0600, or the login Keychain) and the encrypted namespace files can decrypt every secret.cubbydoes not defend against an attacker who is already you on your machine. - An agent that runs arbitrary code. An agent is not sandboxed by
cubby. It can runcubby get --reveal, read the identity file directly, orcubby runa command that exfiltrates the value. The integration (cubby agent) installs a convention that well-behaved agents follow — it is a guardrail against accidental leakage, not an enforcement boundary. - Other processes you own. A decrypted value lives in the environment of the child
process spawned by
cubby run. On some platforms another process running as the same user can inspect that environment. - Key loss. If you lose the age identity, the encrypted namespaces are
unrecoverable.
cubbyhas no escrow or recovery mechanism. Back up the identity yourself.
In short: cubby raises the floor — secrets stop leaking into prompts, logs, and
transcripts by accident — but it trusts your machine and the code your agent runs.
cubby get --reveal prints a secret in plaintext, and cubby get --copy copies it to
the system clipboard — both are deliberate escape hatches, meant for a human at a
terminal. The cubby agent integration asks an agent not to use either, but that is
a convention, not a wall.
Where your agent has a permission system, turn the convention into an enforced rule.
For Claude Code, add deny rules to ~/.claude/settings.json:
{
"permissions": {
"deny": ["Bash(cubby get* --reveal*)", "Bash(cubby get* --copy*)"]
}
}With this in place Claude Code refuses to run any cubby get … --reveal or
cubby get … --copy invocation — the agent cannot disclose a secret value even if
instructed to. (--copy is blocked for the same reason as --reveal: it routes the
plaintext value to the clipboard, where another process could read it.) Other agents
that support command allow/deny lists can be locked down the same way.
This does not close every hole — an agent that runs arbitrary code can still read the
identity file or cubby run a command that exfiltrates the value (see above) — but it
removes the easiest one.
Please do not open a public issue for security problems. Report them privately via GitHub's security advisory form. You will get an acknowledgement, and a fix or mitigation will be coordinated before any public disclosure.