pock://docs

Documentation

Pock encrypts your secrets on your device and never sees the plaintext. Here's how to share files, manage your vault, drive the CLI, and what's happening under the hood.

60 seconds

Quickstart

  1. Install the CLI:
    $ curl -fsSL pock.sh/install | sh
  2. Authenticate - pock login opens your browser and waits for you to approve the device.
  3. Share a file: pock share .env.production --ttl 1h. Pock prints a link and copies the key to your clipboard.
  4. Send the link and the key through different channels. The recipient runs pock receive <id> <key> or drags the saved key onto the web receive page.

one line

Install

The pock binary installs to ~/.pock/bin. Add that directory to your PATH if the installer can't do it for you.

Linux & macOS

$ curl -fsSL pock.sh/install | sh
  pock  installing…
  ✓ downloaded pock 0.5.0 (darwin/arm64)
  ✓ installed → ~/.pock/bin/pock
  → add ~/.pock/bin to your PATH, then run: pock login

Windows (PowerShell)

> irm pock.sh/install.ps1 | iex

device flow

Authenticate

pock login opens your browser and starts a device approval flow - confirm in the browser and the CLI stores a token under ~/.pock. No keys or passwords are typed into the terminal.

$ pock login
→ opening https://pock.sh/cli-auth?code=JABS-X9F2
  waiting for approval in your browser…
✓ approved - logged in as alice@acme.dev

Check who you are, or sign out and wipe the local token:

$ pock whoami
alice@acme.dev · acme.dev · token expires in 29d

$ pock logout
✓ signed out - local token removed

zero-knowledge

Secure sharing

pock share <files…> encrypts any file - .env, JSON, YAML, kubeconfigs - on your machine before anything leaves it. We only ever store ciphertext; the decryption key never touches our servers. Pock prints a link and an out-of-band key - the key is copied to your clipboard. Knowing the link alone is useless. Send the two through different channels.

$ pock share .env.production --ttl 1h
✓ encrypted 1 file · 4.2 KB · x-wing
✓ uploaded envelope · expires in 1h

  link  https://pock.sh/r/3kPq8vN2
  key   pk_aQ7x9…Lr2  (copied to clipboard)

  send the link and the key through different channels.

Combine flags to scope access. Multiple files, recipient allow-lists, and burn-after-read all compose:

$ pock share .env staging.env \
    --ttl 7d --one-time \
    --email alice@acme.dev --email bob@acme.dev \
    --ip 10.0.0.0/8 --note "rotate after use"
✓ encrypted 2 files · 11.8 KB · x-wing
✓ one-time · 2 recipients · 1 ip rule · expires in 7d

  link  https://pock.sh/r/9Zt4mWbK
  key   pk_Vd3k1…Qn8  (copied to clipboard)

Every access is logged (time, IP, geo, account if signed in) and revocable from the web dashboard.

--ttl 30m | 1h | 7d
Lifetime of the share. Accepts durations like 30m, 1h, 7d. Maximum is 7d; an hourly sweep hard-deletes expired ciphertext.
--one-time
Burn after read - the share is destroyed the instant it's first opened.
--email <addr>
Restrict to a verified recipient email. Repeatable to allow several addresses. Enforced server-side, on top of the key.
--domain <company.com>
Allow any address at a domain - *@company.com.
--ip <CIDR>
Restrict access to an IPv4 CIDR range. Repeatable.
--algo <cipher>
Cipher to use: x-wing (default, post-quantum) or xchacha20poly1305 (symmetric).
--note <text>
Attach a short note shown to the recipient before they decrypt.
--json
Emit machine-readable output instead of the pretty summary - handy for scripts and CI.
--no-copy
Don't touch the clipboard; just print the key. Useful on headless hosts.

decrypt

Receiving

The recipient runs pock receive <id> <key>. Pock fetches the envelope, decrypts it locally, and writes the files out - the key never leaves their machine either.

$ pock receive 3kPq8vN2 pk_aQ7x9…Lr2 --out ./secrets
✓ fetched envelope · 1 file
✓ decrypted → ./secrets/.env.production

On the web, navigate to the share link and drag the saved .key file onto the receive page - no clipboard needed, decryption runs in your browser via WASM.

--out <DIR>
Directory to write decrypted files into. Defaults to the current directory.
--force
Overwrite existing files in the output directory instead of aborting.

secret manager

Vault

The vault stores key/value secrets grouped into projects. Each value is encrypted to your own key ("encrypt-to-self") and stored as an opaque blob - Pock never sees the plaintext.

Web (/vault)

  • Create - keygen runs in WASM; your Secret Key and recovery code are shown once (copy and download them).
  • Unlock - enter your passphrase + Secret Key, or use a passkey (Face ID, Touch ID, Windows Hello) for one-touch unlock.
  • Manage - reveal, copy, and edit secrets; add projects; reset the vault to start over.

CLI

# Create a new vault (generates Secret Key + recovery code)
$ pock vault init

# Write secrets
$ pock vault set app DATABASE_URL=postgres://db/prod API_KEY=abc123
set app/DATABASE_URL
set app/API_KEY

# List projects or keys
$ pock vault ls
app

$ pock vault ls app
API_KEY
DATABASE_URL

# Read secrets (prompts for passphrase)
$ pock vault get app
DATABASE_URL=postgres://db/prod
API_KEY=abc123

$ pock vault get app API_KEY
abc123

# Inject secrets into a process (never written to disk)
$ pock run -p app -- printenv DATABASE_URL
postgres://db/prod

pock run -p <project> -- <cmd> injects the project's secrets as environment variables into the child process. They are never written to disk or exposed in the shell's history.

WebAuthn PRF

Touch ID / Passkeys

When you register a passkey - Face ID, Touch ID, Windows Hello, or a hardware security key - on the vault unlock page, Pock uses the WebAuthn PRF extension to derive a deterministic key from your authenticator. That key is never sent to the server - it's derived on-device, used to unwrap your Account Unlock Key, then discarded.

On-device only

The PRF output never leaves the authenticator. Pock's server sees only the wrapped Account Unlock Key blob.

Zero-knowledge

A server breach cannot recover vault plaintext. The key material required to decrypt lives only on your device.

Fallback

If biometrics are unavailable, unlock with your passphrase + Secret Key or the printed recovery code.

under the hood

Crypto core

One audited Rust core (pock-core) compiled to native and WebAssembly powers every surface - CLI and web are byte-compatible.

Key derivation - 2SKD

Argon2id with a two-secret derivation (2SKD): your passphrase is combined with a machine-generated 128-bit Secret Key. A server breach cannot brute-force vault ciphertext without the Secret Key, and a stolen Secret Key is useless without the passphrase.

Ciphers

  • X-Wing (X25519 + ML-KEM-768)default

    Post-quantum hybrid KEM. Secure if either classical (X25519) or post-quantum (ML-KEM-768) stays unbroken. Used for multi-recipient and asymmetric envelope encryption.

  • XChaCha20-Poly1305

    AEAD with a 24-byte random nonce. Constant-time, no AES-NI required. Used for symmetric encryption and as the inner AEAD inside envelope encryption.

  • Ed25519

    Signatures and identity. Used for CLI token signing and authenticating CLI-to-server requests.

Envelope encryption

HPKE-style: KEM encapsulate produces a shared secret - HKDF expands it to a per-item data key - XChaCha20-Poly1305 encrypts the payload. The data key is wrapped to each recipient's public key so multi-recipient shares require only one ciphertext copy.

Zero-knowledge

The server stores ciphertext and metadata. It never holds plaintext, passphrase, or any key material required to decrypt.

Post-quantum

X-Wing is the default for sharing. Even if a quantum computer breaks X25519 today, ML-KEM-768 keeps the ciphertext secure.

Auditable

pock-core is open-source Rust. The same binary is used by the CLI and compiled to WASM for the browser - one target to audit.

portability & compromise recovery

Backup & rotation

Two independent safety nets live in account menu → Vault: an encrypted file backup, and self-service key rotation. Both run entirely on your device.

Encrypted backup (.pockvault)

Export decrypts every secret you can read, serializes them, and seals the result under a passphrase you choose. Argon2id (46 MiB, memory-hard) derives the key and XChaCha20-Poly1305 seals the body. The file is deliberately standalone: it is not bound to your Secret Key or account, so it restores even if you lose everything else. The trade-off is that the backup passphrase is the only thing protecting it, so use a long, unique one.

.pockvault layout
┌───────────┬──────────┬─────────────────┬────────────────────────┐
│ MAGIC (8) │ salt(16) │ argon2 params   │ XChaCha20-Poly1305 body │
│ POCKVLT\x01│          │ m_kib,t,p (12)  │ nonce(24) ‖ ct ‖ tag    │
└───────────┴──────────┴─────────────────┴────────────────────────┘
Import re-derives the key; the auth tag rejects a wrong
passphrase or any tampering (no partial decrypt).

Key rotation

Change passphrase, Rotate Secret Key, and Regenerate recovery code are cheap: they re-wrap your account key (AUK) under the new factor, so no secrets are re-encrypted. Rotated values are shown once; save them.

Rotate identity keys is the deep option for a suspected compromise: a fresh keypair is minted and every secret is re-encrypted to it in one atomic operation. Old-key artifacts (item history, trash) are cleared because they can't be carried across, and team secrets are re-keyed separately by a team admin. Unlock protected namespaces first, or rotation aborts before changing anything.

A plaintext JSON export is also available for migrating to another tool. Treat that file like any password-manager export, since it is unencrypted.

commands

CLI reference

All commands accept --help for full flag listings.

pock login
Device-flow authentication. Opens a browser tab and waits for approval. Stores a token under ~/.pock.
pock logout
Sign out and delete the local token.
pock whoami
Print the authenticated email, org, and token expiry.
pock share <file…> [flags]
Encrypt and upload one or more files. See the Secure sharing section for the full flag list.
pock receive <id> <key> [--out DIR]
Fetch and decrypt a share by ID and key.
pock vault init
Create a new vault. Generates your Secret Key and recovery code (shown once).
pock vault set <project> KEY=VALUE…
Write one or more secrets into a project, encrypted to your key.
pock vault get <project> [KEY]
Decrypt and print secrets for a project, or a single key. Prompts for passphrase.
pock vault ls [project]
List projects, or the keys within a project.
pock vault rm <project> <key>
Delete a secret. Use pock vault mv to rename or move one (--to-project to move across namespaces).
pock vault ns rename|rm
Rename a namespace and its whole subtree, or delete a namespace and its contents.
pock vault env ls|create|add|export
Manage environments. export decrypts the referenced secrets to a .env (stdout or --file).
pock vault import <file>
Import a .env as standalone secrets plus an environment (--env, --folder).
pock gen [-l N | -p -w N]
Generate a strong password or passphrase.
pock vault link
Attach a new machine to your existing vault (Secret Key + passphrase, once). The device-setup / recovery flow.
pock vault machine create <scope> [--github owner/repo]
Mint a scoped machine key for CI (re-encrypts <scope> to a new keypair; decrypts only that subtree). --github writes it straight to a repo's secrets. Also machine ls / machine rm.
pock run -p <project> -- <cmd>
Inject a project's secrets as env vars into a child process (item names become var names). Never written to disk.
pock run -e <environment> -- <cmd>
Inject an environment's secrets (export keys become var names).
env: POCK_TOKEN / POCK_MACHINE_KEY / POCK_SECRET_KEY / POCK_PASSPHRASE
Drive Pock non-interactively in CI - auth with POCK_TOKEN, unlock with a scoped POCK_MACHINE_KEY (best) or your POCK_SECRET_KEY + POCK_PASSPHRASE. See Guides.
pock version
Print the running build and check for a newer release.
pock update
Upgrade the binary in place under ~/.pock/bin.

staying current

Maintenance

pock version prints the build you're running and checks for a newer release. pock update upgrades the binary in place under ~/.pock/bin.

$ pock version
pock 0.5.0 (darwin/arm64)
↑ 0.5.1 available - run `pock update`

$ pock update
↓ updating 0.5.0 → 0.5.1…
✓ pock is now 0.5.1