Skip to main content

burnedsecret-cli (bs)

Command-line interface wrapping the burnedsecret zero-knowledge secrets REST API. All encryption happens client-side; the server never sees plaintext or decryption keys — the key travels only in the URL #k=... fragment, which the server never receives.

pip install burnedsecret-cli
bs auth login
echo "my-secret" | bs secret create

Install

The CLI ships through four channels:

# 1. pip (Python 3.9+)
pip install burnedsecret-cli

# 2. Homebrew (macOS / Linux)
brew install JensrudJ/burnedsecret/bs

# 3. Scoop (Windows)
scoop bucket add burnedsecret https://github.com/JensrudJ/scoop-burnedsecret
scoop install bs

# 4. Standalone binary (no Python needed)
curl -fsSL https://burnedsecret.com/install/cli/install.sh | sh      # POSIX
irm https://burnedsecret.com/install/cli/install.ps1 | iex            # Windows PowerShell

macOS first run: the standalone binary is currently shipped unsigned. On first launch macOS Gatekeeper may block it; right-click → Open, or xattr -d com.apple.quarantine $(which bs) to clear the quarantine flag. (Signed/notarized builds are a follow-up — see the v1 gaps below.)

Quickstart

# 1. Authenticate (opens your browser to authorize this machine)
bs auth login

# 2. Create a secret — prints ONLY the share URL on stdout
url=$(echo "the launch codes" | bs secret create --ttl 1h)
echo "$url"

# 3. Read (and burn) it
bs secret read "$url"

Because the share URL is the only thing on stdout, url=$(... ) captures exactly the URL; every prompt, table, and diagnostic goes to stderr.

Global options

Option Env var Description
--profile NAME BURNEDSECRET_PROFILE Select a config profile (default: default).
--json — Emit the raw SDK shape as JSON on stdout.
--verbose / -v — Extra diagnostics on stderr.
--version — Print the CLI version and exit.

The API key is resolved as BURNEDSECRET_API_KEY (env) > the stored config[profile].api_key.

Command reference

bs secret create

Creates a burn-after-reading secret and prints only the share URL.

Flag Description
--content / -c Secret text. If omitted: stdin pipe → --edit → hidden prompt.
--edit / -e Compose the secret in $EDITOR.
--file / -f Encrypt a file as the secret (max 10 MB). Excludes text input.
--passphrase / -p Add a PBKDF2 passphrase layer (bare flag prompts hidden).
--max-views Reads before the secret burns (1..5, default 1).
--ttl Time to live: 5m / 1h / 1d / 7d (default 1d).
--webhook-url Notify this URL when the secret is read.
--notification-email Email this address when the secret is read.
echo "hunter2" | bs secret create --max-views 3 --ttl 7d
bs secret create --file ./id_rsa --ttl 1h
bs secret create --content "deploy key" --passphrase --ttl 1h   # prompts for passphrase

Web-viewer non-interop caveat: secrets created with --file or --passphrase are decryptable only by an SDK/CLI client. Their share URL will NOT open in the burnedsecret.com web viewer. Plain text secrets without a passphrase remain web-viewer compatible. (After a --file/--passphrase create the CLI also prints a one-line reminder to stderr.)

bs secret read

Reads and burns a secret from its share URL.

Flag Description
URL (argument) Share URL — must include the #k=... key fragment.
--passphrase / -p Passphrase for a protected secret (bare flag prompts hidden).
--output / -o Write file-secret bytes to PATH, or - to stream to stdout.
bs secret read "https://burnedsecret.com/s/abc#k=..."
bs secret read "$url" --passphrase hunter2
bs secret read "$url" --output ./downloaded.bin

bs request create | read

Create a request-for-secret link, then read its fulfillment. The SDK generates an RSA keypair locally; the private key is never sent to the server and cannot be regenerated — without it the fulfillment is permanently unrecoverable. By default create writes the key to <config_dir>/requests/<id>.key (absolute path echoed to stderr).

create flag Description
--prompt What you are asking the recipient to send (required).
--private-key Key destination: a PATH, - (stdout), or env (shell export).
--fields Custom fields: name:type:required;... (type = text|password|textarea).
--ttl 5m / 1h / 1d / 7d.
--webhook-url Notify this URL when the request is fulfilled.
--notification-email Email this address when the request is fulfilled.
url=$(bs request create --prompt "send the AWS key" --ttl 1d)
# ... recipient fulfills it via the link ...
bs request read <request-id> --private-key ~/.config/burnedsecret/requests/<id>.key

read requires --private-key PATH | - (stdin) | env. Free-text fulfillments print as text; custom-field fulfillments print as JSON.

bs key create | list | revoke | whoami

Key management is browser/dashboard-assisted in v1 (see the gaps below).

Command Behavior
key create Alias of bs auth login — the PKCE exchange mints the labeled key.
key list Prints your dashboard /keys URL (view/revoke there).
key revoke Prints the dashboard /keys URL; the CLI never network-revokes a key.
key whoami Shows the stored key_prefix/hostname/base_url — no network call.

The CLI never mints sibling keys from a stored key: minting from a leaked key would be a privilege-escalation surface.

bs auth login | logout | status

Command Behavior
auth login Browser PKCE flow; stores a hostname-labeled key. The key is never printed.
auth logout Forgets the local key (does not revoke server-side — use the dashboard).
auth status Shows the profile's identity (configured?, source env/file, prefix, host).

bs config list-profiles

Lists configured profiles with their key_prefix/base_url.

Configuration & storage

Config lives at:

  • Windows: %APPDATA%\burnedsecret\config.toml
  • POSIX: ${XDG_CONFIG_HOME:-~/.config}/burnedsecret/config.toml

On POSIX the config (and any persisted request key) is written with 0600 permissions so only the owner can read the stored API key. Request private keys default to <config_dir>/requests/<id>.key.

Environment overrides: BURNEDSECRET_API_KEY, BURNEDSECRET_PROFILE.

Exit codes

Result data is always on stdout; diagnostics/errors/prompts are on stderr.

Code Meaning
0 success
1 generic error
2 invalid arguments / usage
3 authentication error
4 not found
5 rate limited

The same table is shown in bs --help; see docs/exit-codes.md for the canonical reference and scripting examples.

The browser-auth recipe (PKCE + loopback)

bs auth login implements a reusable pattern for authenticating a CLI/native app through the browser without ever putting a secret in a URL or asking the user to paste a token. It is a textbook implementation of PKCE (RFC 7636) plus the loopback-redirect native-app flow (RFC 8252), and the recipe transfers to any CLI that needs browser auth — not just BurnedSecret:

  1. Generate ephemeral secrets locally. A random CSRF state and a PKCE pair: verifier = base64url(32 random bytes), challenge = base64url(sha256(verifier)) (S256). The verifier never leaves the machine; only the challenge is sent.
  2. Bind a one-shot loopback server. Grab a free 127.0.0.1:<port> and start a single-request HTTP server in a thread. This is the redirect target — no public callback host, no firewall holes.
  3. Open the browser to the consent page, carrying only public values: the loopback callback, the CSRF state, the S256 code_challenge, and a hostname label for the key. The URL is also echoed to stderr so a headless or no-default-browser user can paste it manually.
  4. Capture and validate the callback. The browser redirects to the loopback server with ?code=&state=. The handler constant-comparison-checks the returned state against the one it generated — a mismatch is a hard abort that captures no code, so no exchange ever happens. The callback carries only code + state; the API key is never in any URL.
  5. Exchange the single-use code for the key. POST {code, code_verifier} to the exchange endpoint. The server recomputes sha256(verifier) and constant-time compares it to the stored challenge, proving the same client that started the flow is finishing it. The API key is returned only in the response body, then stored chmod-600 and never printed.

Security rationale, in one line each:

  • CSRF state — prevents a forged callback from injecting an attacker's code.
  • PKCE verifier/challenge — binds the code to this client; a stolen code is useless without the verifier, which never traveled over the network.
  • Key never in the callback URL — URLs leak (history, logs, referrers); the key lives only in the exchange response body and on-disk chmod-600.
  • Single-use, short-TTL code — narrows the window for replay.

Documented v1 gaps & follow-ups

These are deliberate v1 scope decisions, recorded here rather than silently dropped:

  • Access-restriction flags are NOT in v1. --access-cidrs, --access-countries, and --require-captcha are not available — the shipped REST create_secret shape has no such parameters; adding them needs an SDK extension (D-06 deviation).
  • OS keyring storage is deferred to v2. Keys are stored in a chmod-600 config file, not the OS keychain/credential manager.
  • bs secret read --copy (clipboard) is deferred. Pipe to your platform's clipboard tool (pbcopy / clip / wl-copy) in the meantime.
  • bs secret create --bulk is deferred. Create secrets one at a time (or loop in your shell) for now.
  • Polished tab-completion install is deferred. Typer's completion machinery is wired, but a one-command shell-completion installer is a follow-up.
  • bs key list / bs key revoke are browser/dashboard-assisted in v1. They print your dashboard /keys URL rather than calling an API-key-authenticated keys endpoint (which would be a privilege-escalation surface). A token-cache-backed headless listing is a v2 option.
  • Standalone macOS binaries are currently unsigned (see the install note); signing/notarization is a follow-up.
  • Chocolatey is a deliberate fast-follow; Scoop covers the Windows package-manager path for v1.

CI usage

Automation does not run the browser flow. CI uses a pre-minted BURNEDSECRET_API_KEY env var; none of the bs auth/bs key commands are needed in a pipeline.

Metadata

Release files for burnedsecret-cli 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for burnedsecret-cli 1.0.2
File Size Uploaded
burnedsecret_cli-1.0.2.tar.gz 45.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for burnedsecret-cli 1.0.2
File Interpreter ABI Platform
burnedsecret_cli-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 81.2 kB

Release files / burnedsecret_cli-1.0.2.tar.gz

Download URL burnedsecret_cli-1.0.2.tar.gz
Size 45.9 kB
Tags Source
SHA-256 checksum
How to use checksums
ed1d789f432fc0f0e1c9bd6d115c2a6ce7f57013eae97e0d0477ac46e3e8cfeb
BLAKE2b-256 checksum
How to use checksums
1864767653f926619e94dfd3728367c96d224993d4bcc8a7f92483ac67e3a175
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.5

Release files / burnedsecret_cli-1.0.2-py3-none-any.whl

Download URL burnedsecret_cli-1.0.2-py3-none-any.whl
Size 35.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8c460fa1fd2a398b36779190c6fdb51baeca3b3db205537820d659b072d11d0c
BLAKE2b-256 checksum
How to use checksums
869e38e30ea3f946839c343bfb3a678581d6e7465059e35fc6e4c17de941d484
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.5

Release history Release notifications | RSS feed

1.0.4

2 release files

1.0.3

2 release files

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page