Free · Open source (MIT) · Self-hosted

Your team’s secrets.Decrypted only on your server.

An open-source vault you run yourself: values are decrypted only on your server, every reveal needs your passkey or authenticator app, and every read is logged.

brew install victorlunam/tap/kuukura

Installs ku and kuukura (the same program). Then: deploy the server.

The confirmation page on vault.example.com: Confirm it's you. A command in your terminal is asking you to confirm: Reveal STRIPE_KEY app:shop env:prod. Confirm with your passkey, or with a 6-digit code from your authenticator app.
A reveal opens this page on your own server. It says exactly what you are confirming.
$ ku run -- npm start
> shop@1.0.0 start
> node server.js
listening on :3000
ku run starts your program with its secrets in the environment. The values never reach your screen.

Who kuukura is for

Good fit

  • A small team that wants to share secrets without sharing passwords.

  • One organization. One instance serves one organization.

  • You can run Docker. One container, SQLite by default.

Not a fit yet

  • SSO or SAML sign-in.

  • Dynamic secrets: short-lived credentials generated on demand.

  • Several organizations in one instance.

Every secret is sealed with its own key.

Opened only on your server, and only for who you grant.

Why kuukura

.env files passed around in chat.API keys in a shared password manager.A heavyweight vault with seal, unseal and a policy language.And nobody can say who read what last week.

One server. One database. Three ideas you can learn in a minute: tags, grants, people.

A tag labels a secret; a grant gives a person or a CI token read or write access to the secrets with those tags.

Four steps

Hand a secret to a program without handing it to a person.

$ ku profile add work \
    --url https://vault.example.com
✓ Added profile work
$ ku login
profile: work
Opening your browser to sign in.
✓ Signed in to work
$ ku secret set DATABASE_URL app:shop
Value (hidden): ••••••••••••••••
DATABASE_URL is new. Create it? (y/N) y
✓ Saved DATABASE_URL (version 1)
$ ku link shop
✓ Linked this folder to shop
$ ku run -- npm start
> shop@1.0.0 start
> node server.js
listening on :3000
$ 
  1. Step 1

    Point it at your server.

    A profile is a name and the address of your vault. Nothing secret is stored in it.

  2. Step 2

    Sign in with Google, then your passkey.

    A passkey or authenticator app is required on every sign-in. The session is kept in your system keychain for 8 hours, 1 hour idle.

  3. Step 3

    Save a value. Never as an argument.

    It comes from a hidden prompt, so it stays out of your shell history and the process list. The server encrypts it under a fresh data key.

  4. Step 4

    Run your app with its secrets.

    Link the folder to an app once. ku run starts your command with the secrets you may read in its environment, and passes its output and exit code through.

Deploy

Runs anywhere you run Docker.

One container and the published image. SQLite by default, Postgres when you want it. Nothing to compile.

Read the deploy guide

# with the compose file, .env and a master key in place (see the guide):
docker compose up -d
docker compose exec kuukura /ku-server user invite you@example.com --admin
docker compose exec -it kuukura /ku-server key show
Back up the master key right away: without it nobody, including the maintainer, can read your data. The full steps

The confirmation moment

A reveal needs you. Not just your session.

Revealing a value, saving it to a file or turning confirmation off opens a page on your own server. It shows exactly what you are confirming, then asks for your passkey or a code from your authenticator app.

  • Passkeys with user verification, or an authenticator app.

  • Single use and 60 seconds, bound to you, the action and the secrets.

  • Machines never confirm. A CI token can never reveal a value, and an agent cannot give your passkey.

  • Mark a secret requires_authorize and even ku run asks first.

What your team sees, from invite to done

  1. The invitation page: You're invited. Continue with Google.
    1 The invitation
  2. Secure your account: add a passkey, or use an authenticator app.
    2 Add a passkey
  3. Confirm it's you: Reveal STRIPE_KEY app:shop env:prod.
    3 Confirm
  4. You're all set: your account is ready. In your terminal, add this server and sign in.
    4 All set

How it works

The CLI is a channel.
The server holds the keys.

Your server checks the grant, decrypts, and writes the decision to the audit log. The database only ever holds ciphertext (the encrypted values) and wrapped keys: each secret version gets its own key, locked by your master key (envelope encryption).

The ku CLI, CI jobs and AI agents talk to ku-server over TLS. The server authorizes, decrypts and audits. The database, SQLite or Postgres, holds only ciphertext and wrapped keys. The master key comes from a file, an environment variable or AWS KMS. Google is used for sign-in only, and confirmations use your passkey or authenticator app. TLSreads and writeswraps the data keysku (CLI)peopleCI jobmachine tokenAI agentthrough ku runku-serveryour hostauthorizegrants per tagdecryptkey per versionaudithash chainSQLite or Postgresciphertext andwrapped keys onlyMaster keyfile, env var or AWS KMSGooglesign-in onlyYour passkeyor authenticator app,for confirmations The ku CLI, CI jobs and AI agents talk to ku-server over TLS. The server authorizes, decrypts and audits. The database, SQLite or Postgres, holds only ciphertext and wrapped keys. The master key comes from a file, an environment variable or AWS KMS. Google is used for sign-in only, and confirmations use your passkey or authenticator app. TLSku (CLI)peopleCI jobmachine tokenAI agentvia ku runku-serveryour hostauthorizegrantsdecryptdata keysaudithash chainSQLite or Postgresciphertext andwrapped keys onlyMaster keyfile, env varor AWS KMSGooglesign-in onlyYour passkeyor authenticatorapp: confirmations

Built for AI coding agents

Let agents use secrets without handing them over.

Add SKILL.md to your agent. It teaches ku run and ku secret list, and what never to do: no reveals, no printing values, no values in commands or files.

Secrets live in a vault. You run commands with them; you never read them.

Do

  • ku secret list app:shop env:devnames, versions and tags, never values
  • ku run env:dev -- npm run devsecrets injected as env vars
  • If a secret is blocked or you are not permitted, stop and tell the user.

Never

  • ku secret get --revealor --out: they need the user’s own confirmation
  • Print, echo, log or paste a secret value anywhere.
  • Put a value in a command line, a URL, a config file or a test fixture.
The full skill

Security, honestly

Every claim comes with a place to check it.

Things you can verify, not take on trust. These are self-reviews and published evidence, not third-party certifications.

  • Threats, controls and what is not defendedThreat model
  • A self-review against OWASP ASVS Level 2 (a checklist of application-security requirements), with its open items listedASVS L2 self-review
  • Nothing is readable by default, and admins have no secret access by roleGrants
  • An audit log you can check: each entry carries a fingerprint of the one before it (hash-chained), so edits showku-server audit verify
  • Static analysis and dependency checks in CI (staticcheck, gosec, govulncheck)ci.yml
v=YEAR.MONTH.N
gh attestation verify oci://ghcr.io/victorlunam/kuukura:$v --repo victorlunam/kuukura
cosign verify ghcr.io/victorlunam/kuukura:$v \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-identity https://github.com/victorlunam/kuukura/.github/workflows/release.yml@refs/tags/v$v
These prove an artifact came from this repository’s workflow at that tag; they do not prove the source has no bugs.

What kuukura does not protect against

  • Someone with both the database and the master key reads everything. That is why the key lives outside the database and /data.

  • A compromised server host. Root access, a debugger or a memory dump exposes keys and plaintext while the server runs.

  • A malicious admin with host or database access, who can mint invites, replace the binary or rewrite the audit chain.

  • A stolen session on an unlocked laptop can ku run plain secrets until it expires (8 hours, 1 hour idle). Reveals still need your second factor.

  • Phishing of authenticator codes and recovery codes, which passkeys resist and these do not.

Agents that print what ku run injects are covered in the agent guide.

How it compares

Choose the right tool. Even if it isn’t this one.

ToolHosting and licenseChoose it if
kuukuraSelf-hosted, one organization. MIT.You are one small team and want a vault you can operate in an afternoon
InfisicalSelf-hosted or cloud. MIT core, paid enterprise edition under ee.You want a broader platform (dynamic secrets are among its features) and can use its enterprise tier where needed
OpenBaoSelf-hosted. MPL-2.0.You need dynamic credentials with leases and revocation, many backends or large-scale policy
SOPSA file tool, no server. MPL-2.0.Your secrets live in Git and you do not need access logs or per-person grants
.env filesNoneThrowaway local work with nothing worth protecting

Sources, last checked 2026-10-19: the repository pages linked above (licenses and feature lists as stated by each project). Open an issue if a row is out of date.

Open source

MIT licensed. One maintainer. No surprises.

  • MIT license

    Free to use, read and change. There is no hosted version: you run it yourself.

    License
  • Calendar versions

    Releases are YEAR.MONTH.N. Pin one in production and read the notes before upgrading.

    Changelog
  • Contributions welcome

    Issues and pull requests are welcome. A short issue before a large change saves everyone time.

    Contributing
  • Report privately

    Found a vulnerability? Use GitHub’s private vulnerability reporting, not a public issue.

    Security policy

Not yet: a third-party security audit, and a requirement-by-requirement mapping to the ASVS checklist.

Questions

What does it cost?

Nothing. kuukura is free and MIT licensed, and there is no hosted version, so there is no subscription: you pay only for the server you run it on.

How do I back up?

Back up the database (the /data volume or Postgres) and the master key as two different things in two different places. Run ku-server key show once per key version and keep the text in a password manager; the key file lives in its own /keys volume.

Can an AI agent see values?

Not through the commands it is taught: ku run injects them, and reveals need your passkey or code. But a command it runs can print its own environment. Treat that as accepted risk and use low-value secrets (details).

What if I lose my passkey?

Use a recovery code (you get ten at enrollment). If you lost those too, someone with a shell on the server runs ku-server user reset-factors you@example.com and you enroll again through a 15-minute link.

What if the server is down?

ku run cannot fetch secrets until it is back, because values are decrypted only on the server. The server restarts by reading the key again; there is nothing to unseal. Run it as a restartable container with its volumes backed up.

Why not Vault or OpenBao?

They do more, including dynamic secrets (short-lived credentials generated on demand), and cost more to run. kuukura trades breadth for a small system you can understand and operate, with no unseal ceremony (the manual key entry some vaults need at every start). If you need their features, use them.

Can I use Postgres?

Yes: set VAULT_STORAGE=postgres. The audit log is insert-only, enforced with database grants (setup). SQLite is the default.

Free · MIT · runs on your server

A vault you can operate in an afternoon.

brew install victorlunam/tap/kuukura