Bring Your Own Vault

Your secrets stay in your vault.
Only references ever leave it.

SecRefs expands declarative sec:// URIs directly in memory, at the moment they're used. Your vault stays the system of record - SecRefs resolves secrets, and never stores one.

quickstart.sh
pnpm add @secrefs/node
+ @secrefs/node 0.1.0
echo 'DB_PASSWORD=sec://aws/prod/db#password' >> .env
npx secrefs run -- node server.js
secrefs: resolved 1 secret reference(s): DB_PASSWORD
server listening on :3000

You already have a vault. Stop copying secrets out of it.

Every plaintext secret that leaves your vault - into a .env file, a CI variable, a teammate's clipboard - is a copy you now have to track, rotate, and eventually leak. SecRefs replaces the copy with a pointer.

.env sprawl
.env (committed to 6 places, rotated in 0)
DB_PASSWORD=correcthorsebatterystaple
STRIPE_KEY=sk_live_51N...
VAULT_TOKEN=hvs.CAESIJ...
# ^ now living on 3 laptops, in Slack, and in CI logs
  • Plaintext secrets on disk, in shell history, in CI logs
  • No single source of truth once a value is copy-pasted
  • Rotation means chasing down every place a copy landed
SecRefs
.env (safe to commit)
DB_PASSWORD=sec://aws/prod/db#password
STRIPE_KEY=sec://vault/secret/data/stripe#key
VAULT_TOKEN=sec://local/mock-vault-token
# ^ just pointers - the real values never left the vault
  • Values expand in memory, at the moment they're used
  • Your vault stays the single source of truth
  • Rotate in the vault; running apps pick it up without a restart

How it works

01

Write a reference, not a value

Put sec://aws/prod/db#password in .env instead of the plaintext password. It's safe to commit.

02

Run your app through secrefs

secrefs run -- node server.js intercepts your environment before your app boots.

03

References resolve in memory

Every sec:// value is fetched from its real vault concurrently, entirely in the CLI's memory.

04

Your process gets real values

The child process inherits a fully-hydrated environment. Nothing was ever written to disk - and a reference resolved at use time picks up a rotation without a restart.

Interactive

See the expansion happen, safely

Paste a mock .env, pick which lines are mock provider secrets, and watch SecRefs validate and expand them entirely in your browser's memory. Nothing here ever leaves your machine - there's no backend behind this sandbox.

.env
4 sec:// references detected
Resolved entirely in your browser's memory. Nothing is sent over the network.
resolved environment

Hit Expand to simulate resolving every sec:// reference above.

Bring your own vault

AWS Secrets Manager

sec://aws/prod/db#password

Ambient AWS credentials or an IAM role - never a static key in your config.

HashiCorp Vault

sec://vault/kv/stripe#key

KV v1 & v2, authenticated via VAULT_ADDR / VAULT_TOKEN already in your environment.

Bitwarden Secrets Manager

sec://bitwarden/stripe-key

End-to-end encrypted, decrypted client-side via a machine account token. Address a secret by name or UUID. Self-hosted instances supported.

Local (dev only)

sec://local/mock-db#password

A gitignored .secrefs.local.json for teammates who don't have vault access yet.

Pass-through

The same idea, pointed outward.

A reference works just as well when the thing reading it isn't yours. Give a vendor sec://acme/stripe#key instead of the key, and they resolve it when they use it - so rotating at the source never breaks their integration, and revoking their access never touches anyone else's.

Their database stops holding your credentials. Yours stays the only place the value lives.

If you're a vendor, start here
what the vendor stores
# not your key - a pointer to it
sec://acme/stripe#key
# you rotate at the source
# their next call gets the new value
# nothing on their side changed

Quickstart

Node.js / CLI
// package.json
pnpm add @secrefs/node
// .env
DB_PASSWORD=sec://aws/prod/db#password
secrefs run -- node server.js
Node.js / library
import { secRefs } from '@secrefs/node';
await secRefs.init();
// process.env.DB_PASSWORD is now the real value
const key = await secRefs.expandString(
'sec://vault/secret/data/stripe#key'
);
Python
pip install secrefs
from secrefs import sec_refs
await sec_refs.init()
# os.environ['DB_PASSWORD'] is now the real value
secrefs-py run -- python app.py