Secrets ยท Storage
The secrets you'd otherwise drop in a .env file.
Secrets is a small KMS-style store, scoped to your org and addressed by path โ /app/prod/db_url instead of an opaque ID. Every value is encrypted at rest with AES-256-GCM, versioned on update, and reveal is the only call that returns plaintext. It's also the call worth watching in the audit log, because it's logged every time.
$ exc secret create --path /app/prod/db_url --from-stdin
$ exc secret create --path /app/prod/db_url --from-stdin paste the value, then Ctrl-D $ exc secret reveal --path /app/prod/db_url postgres://app:[email protected]:5432/app $ exc secret events --path /app/prod/db_url 2026-06-12 09:14 reveal api-token-7 ok
What's audited
The only call that touches plaintext is reveal โ and that one is always in the log.
Calls that don't touch plaintext โ list, get, lookup, version add โ are safe to use for metadata checks. Reveal only when the application actually needs the value.
| Operation | Returns plaintext? | Audited? |
|---|---|---|
| create / version add | no | yes |
| list / get / lookup | no | yes |
| reveal | yes | yes |
| events | audit log itself | โ |
| delete (soft) | no | yes |
Rotation
Old versions stay readable on purpose.
version add writes a new version that becomes the default for reveal, but the old version stays readable with --version <n> โ useful during a rolling deploy where some consumers still have the old value cached. Identify secrets by path or by the stable integer id if you might rename the path later.
- --out PATH writes the value to a file with mode 0600
- --copy puts the value on the clipboard, --env VAR emits a shell-safe export
- Soft-delete frees the path for re-creation โ there is no undo
$ exc secret version add --path /app/prod/db_url \ --value 'postgres://app:[email protected]:5432/app' $ exc secret version list --path /app/prod/db_url v1 2026-04-02 v2 2026-06-12 (default) $ exc secret reveal --path /app/prod/db_url --version 1 postgres://app:[email protected]:5432/app
Audit log
The audit log names the identity behind each reveal.
exc secret events reads the audit log for one path: every create, version add, reveal, and delete, with the calling identity and a result. It's the first thing to check when a credential might have leaked, and the last thing to check before you trust a rotation went clean.
- Scoped to a path โ --path /app/prod/db_url
- Shows the identity that called reveal, not just that it happened
- Covers create, version add, reveal, and delete in one timeline
$ exc secret events --path /app/prod/db_url 2026-06-12 09:14 reveal api-token-7 ok 2026-06-12 08:55 version add deploy-bot ok 2026-04-02 14:02 create api-token-3 ok
When to use it
Secrets is built for long-lived credentials, not for every value your app touches.
Use it for
- Long-lived credentials shared between several services or VMs
- Anything you want a clear audit log on
- Values that change less than once a day
Don't use it for
- Per-request ephemeral tokens โ fetch from the source each time
- Public configuration โ plain config files or env vars are fine
- High-throughput hot paths โ cache the plaintext after the first reveal
Get started
Your database password shouldn't live in .bash_history.
Put it in Secrets, reveal it only where the app needs it, and use exc secret events to verify the access trail.
$ exc secret create --path /app/prod/db_url --from-stdin