No description
  • Zig 85.7%
  • JavaScript 8.5%
  • CSS 1.9%
  • HTML 1.5%
  • Nix 1.4%
  • Other 1%
Find a file
2026-05-08 23:52:32 +02:00
extension/chrome added AI slop for browser extension 2026-05-08 23:46:57 +02:00
native-messaging/chrome added AI slop for browser extension 2026-05-08 23:46:57 +02:00
src added AI slop for browser extension 2026-05-08 23:46:57 +02:00
tools added AI slop for browser extension 2026-05-08 23:46:57 +02:00
.gitignore update 2026-05-07 11:40:31 +02:00
build.zig added AI slop for browser extension 2026-05-08 23:46:57 +02:00
build.zig.zon added AI slop for browser extension 2026-05-08 23:46:57 +02:00
flake.lock init 2026-05-05 20:34:39 +02:00
flake.nix init 2026-05-05 20:34:39 +02:00
README.md added AI slop for browser extension 2026-05-08 23:46:57 +02:00
TODO.md added AI slop for browser extension 2026-05-08 23:52:32 +02:00

pak

pak is a small Zig password manager prototype backed by SQLite. It stores named secrets encrypted with ChaCha20-Poly1305. The master password is stretched with Argon2id, and every vault stores an encrypted verifier so wrong passwords can be rejected before decrypting any saved secret.

This is a prototype, not a security audit.

Development

nix develop
zig build
zig build test

The default vault path is pak.db. Use -v or --path to target another file.

Website

Build the static website and release binaries:

zig build website

The output is written to zig-out/site, with compiled release binaries in zig-out/site/releases.

Deploy the generated site with rsync:

zig build deploy-website -Dwebsite-dest='user@host:/srv/www/pak/'

Create A Vault

Create a new vault:

pak init -p 'MASTER_PASSWORD'

Create a vault at a specific path:

pak init -v work.db -p 'MASTER_PASSWORD'

init creates the SQLite database, stores the key-derivation salt, and writes an encrypted verifier record.

Verify A Vault Password

pak open -p 'MASTER_PASSWORD'
pak open -v work.db -p 'MASTER_PASSWORD'

On success:

verifier: ok
opened

With a wrong password, the verifier fails and no secrets are decrypted.

Store Secrets

Set or replace a secret:

pak set -n github-token -s 'ghp_secret' -p 'MASTER_PASSWORD'
pak set -v work.db -n deploy-key -s 'secret text' -p 'MASTER_PASSWORD'

Secret names are stored in plaintext so they can be listed without unlocking the vault. Secret values are encrypted. The secret name is included in the AEAD AAD, so moving encrypted payloads between names fails authentication.

Read Secrets

Get one secret value:

pak get -n github-token -p 'MASTER_PASSWORD'
pak get -v work.db -n deploy-key -p 'MASTER_PASSWORD'

If the name does not exist, pak reports that the secret was not found.

List Secrets

List secret names without unlocking values:

pak list
pak list -v work.db

pak vault is an alias for the same list operation:

pak vault

Pass a password source to include decrypted values:

pak list -p 'MASTER_PASSWORD'
pak vault -v work.db -p 'MASTER_PASSWORD'

Output with values is tab-separated:

github-token    ghp_secret
deploy-key      secret text

macOS Keychain Passwords

Instead of passing -p, pak can read the master password from the macOS Keychain with -k or --keychain.

By default, it looks up:

service: pak
account: <vault path>

For the default pak.db vault, store the password like this:

security add-generic-password -s pak -a pak.db -w 'MASTER_PASSWORD' -U

Then use:

pak open --keychain
pak set -n github-token -s 'ghp_secret' -k
pak get -n github-token -k
pak list -k

For a custom vault path:

security add-generic-password -s pak -a work.db -w 'MASTER_PASSWORD' -U
pak get -v work.db -n deploy-key -k

You can override the Keychain service and account:

pak get -n github-token --keychain \
  --keychain-service pak \
  --keychain-account pak.db

If -p/--password is provided, it takes precedence over -k/--keychain.

Chrome Browser Integration

The repository includes a Chrome extension and a Native Messaging host.

Build the CLI and host binary:

zig build

Load the extension from extension/chrome with Chrome's "Load unpacked" button, then copy the generated extension ID from chrome://extensions.

Register the native host for that extension ID:

native-messaging/chrome/install-host.sh CHROME_EXTENSION_ID

By default the installer points Chrome at zig-out/bin/pak-native-host. Pass a second argument to use another installed host path:

native-messaging/chrome/install-host.sh CHROME_EXTENSION_ID /usr/local/bin/pak-native-host

The extension talks to pak-native-host over Chrome Native Messaging using length-prefixed JSON. The host currently keeps the unlocked vault in its own process while Chrome holds the native messaging port open. The protocol is intentionally small: status, unlock, lock, list, get, and set.

Command Reference

The block below is generated from the same usage text printed by pak --help. Run zig build update-readme to refresh it.

pak - encrypted SQLite secret vault

Usage:
  pak init [-v PATH] (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
  pak open [-v PATH] (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
  pak set  [-v PATH] -n NAME -s SECRET (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
  pak get  [-v PATH] -n NAME (-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])
  pak list [-v PATH] [(-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])]
  pak vault [-v PATH] [(-p PASSWORD | -k|--keychain [--keychain-service S] [--keychain-account A])]

Commands:
  init     Create a new vault database and verifier record.
  open     Verify that the master password unlocks the vault.
  set      Create or replace an encrypted named secret.
  get      Decrypt and print one named secret.
  list     List secret names. With a password source, include values.
  vault    Alias for list.

Options:
  -v, --path PATH             Vault database path. Defaults to pak.db.
  -p, --password PASSWORD     Master password. Takes precedence over -k/--keychain.
  -n, --name NAME             Secret name for get/set.
  -s, --secret SECRET         Secret value for set.
  -k, --keychain              Read master password from macOS Keychain.
      --keychain-service S    Keychain service. Defaults to pak.
      --keychain-account A    Keychain account. Defaults to the vault path.
      --help                  Show this help.

Examples:
  pak init -p 'MASTER_PASSWORD'
  pak set -n github-token -s 'ghp_secret' -p 'MASTER_PASSWORD'
  pak get -n github-token -p 'MASTER_PASSWORD'
  pak list
  pak list -p 'MASTER_PASSWORD'
  security add-generic-password -s pak -a pak.db -w 'MASTER_PASSWORD' -U
  pak get -n github-token -k

Notes

The current CLI is intentionally simple. Passwords passed with -p can be visible through shell history or process listings; prefer -k/--keychain for local interactive use. Decrypted values are printed to stdout by get and by list/vault when a password source is provided.