Threat model

What Secretariat protects, and what it doesn't

Secretariat is built against accidents: a key landing in an agent's context, a log or a commit. It is not a sandbox. This page says where the line is, so you can decide what else you need.

Applies to Secretariat 1.7.

Protects against

  • Keys in plain .env files that an agent reads, greps or summarizes
  • Values printed by a program and pulled into the agent's context
  • Values in tool output that ends up in logs or transcripts
  • Committing a value you have stored in Secretariat
  • Forgotten copies in Cloudflare, Supabase, GitHub or on servers after you rotate a key

Does not protect against

  • An agent that deliberately extracts a value it is allowed to run with
  • Values written to files instead of printed
  • Malware running with your user rights
  • A compromised Apple Account or iCloud keychain
  • Secrets Secretariat doesn't know about

How each layer works

No plain files

Values live in your iCloud keychain, not in your project folders. secretariat run hands them to the program as environment variables; key files become temporary files with mode 0600. An agent that reads your project finds profile and item names, not values. Fields marked only-for-me never reach any program.

Output masking

When stdout or stderr is not a terminal, which is the case when an agent or a pipe reads it, Secretariat replaces every value it handed to the program with [masked path/field]. This catches the common accident: a debug print, a stack trace with the config, a verbose CLI.

Limits you should know:

Touch ID approval per item: the hard boundary

For an item with approval switched on, every run, push or inject that needs it waits for your fingerprint. An agent can switch approval on for an item, never off; that is only possible in the app.

This is the one layer that holds against an agent that is trying. Without it, the reality is simple: an agent running as your user can call secretariat run PROFILE -- env > values.txt itself, or any program that writes its environment to a file, and then read the file. No tool can fully hide a secret from a process that runs as the same user and is allowed to use it.

Approval only helps if you read the prompt. Approve when you started the command or expected it, and decline otherwise.

Commit guard

The git pre-commit hook compares staged changes with the values Secretariat knows and refuses the commit if one appears. It catches your real values, including ones no pattern scanner would recognize. It does not catch secrets you never stored in Secretariat, values shorter than 8 characters, or commits made with git commit --no-verify, which skips all hooks.

Targets and rotation

Secretariat remembers where it pushed each value: Cloudflare Workers, Supabase, GitHub, Linux env files over ssh. After a rotation, secretariat targets lists every copy that is now stale. It knows only the copies it pushed itself, not ones you placed by hand.

Out of scope

Malware with your user rights

Software that runs as you can do what you can do: start programs through Secretariat, read their environment, wait for you to approve a prompt. Secretariat doesn't defend against a compromised user account.

Your Apple Account and iCloud keychain

Sync is Apple's iCloud keychain. Whoever controls your Apple Account and can add a device to your keychain can read what is in it. Secretariat has no server of its own, so there is nothing else to break into, and nothing else to rely on.

The services your keys belong to

Once a program has a key, it can do whatever the key allows. Secretariat doesn't limit what a key can do at the provider.

Recommendations

Reporting a problem

If you find a way around a boundary described here, please email business@moinsen.dev. The source is available on GitHub, so you can check these claims against the code.