CLI
v1.0.0

CLI Reference

secrettnl is a zero-dependency terminal tool for pushing and pulling end-to-end encrypted secrets. Every byte is encrypted on your machine before any network call is made.

AES-256-GCM
Burn after read
Zero server knowledge
TTL support
Webhook callbacks

#Installation

No global install required. Use npx to run directly from the npm registry:

bash
npx secrettnl [command] [options]

Or install globally for repeated use:

bash
npm install -g secrettnl
ℹ️
Requires Node.js ≥ 18. The CLI uses the built-in crypto module — no external encryption dependencies.

#secrettnl push

Encrypts content locally using AES-256-GCM and uploads the ciphertext to the SecretTunnel server. Returns a one-time share URL with the decryption key embedded in the URL fragment.

Signature

bash
secrettnl push <content> [--file <path>] [--ttl <duration>] [--password <value>] [--webhook <url>]
ℹ️
Either provide <content> as a positional argument or use --file. If both are given, --file takes priority.

Flags

FlagTypeStatusDefaultDescription
--file, -fstring
optional
Path to a file to push. Reads the entire file contents and encrypts them. Supports .env, .json, or any plaintext file.
--ttlstring
optional
24hTime-to-live. Supported formats: 30s, 15m, 1h, 7d, or raw seconds like 3600.
--passwordstring
optional
Optional password for an extra encryption layer. The recipient must provide the same password when pulling.
--webhookstring (URL)
optional
HTTPS URL called when the secret is viewed. POSTs { token, viewedAt, viewerIp } with a 5-second timeout via Upstash QStash.

Examples

Push inline text

bash
secrettnl push "DATABASE_URL=postgres://user:pass@localhost/db"

Push a .env file

bash
secrettnl push --file .env.production

Custom TTL — expires in 30 minutes

bash
secrettnl push "my secret" --ttl 30m

Password-protected push

bash
secrettnl push "my secret" --password mypass123

Full example with all flags

bash
secrettnl push \
  --file .env.production \
  --ttl 1h \
  --password mypass123 \
  --webhook https://hooks.example.com/secret-viewed

Output

On success the CLI prints a share URL with the decryption key embedded in the URL hash fragment:

output
✓ Secret created

Share URL:
  https://secrettunnel.vercel.app/s/abc12345#key=aB3dK9YzXq...

⚑ Burn-after-read · Expires in 1h
⚠️
The key after # is never sent to the server. Do not truncate the URL when sharing — the full fragment must be preserved.

#secrettnl pull

Fetches and decrypts a one-time secret by its share URL or token. This action is irreversible — the secret is permanently destroyed on the server the moment it is retrieved.

Signature

bash
secrettnl pull <share-url | token> [--key <base64>] [--password <value>] [--output <path | ->]

Flags

FlagTypeStatusDefaultDescription
--keystring (base64)
optional
The base64-encoded AES key. Only needed when passing a bare token. When passing the full URL the key is parsed automatically from the #key= fragment.
--passwordstring
optional
Required only if the secret was pushed with --password. If omitted for a password-protected secret, decryption will fail.
--output, -ostring | -
optional
Path to write the decrypted plaintext. Use - to stream to stdout. If the file already exists, the CLI prompts before overwriting.

Examples

Pull using the full URL (recommended)

bash
secrettnl pull "https://secrettunnel.vercel.app/s/abc12345#key=aB3dK9Yz..."

Pull using a bare token and explicit key

bash
secrettnl pull abc12345 --key "aB3dK9Yz..."

Pull and write directly to .env

bash
secrettnl pull "https://secrettunnel.vercel.app/s/abc12345#key=..." --output .env

Pull a password-protected secret

bash
secrettnl pull "https://secrettunnel.vercel.app/s/abc12345#key=..." --password mypass123

Stream to stdout for piping

bash
secrettnl pull "https://secrettunnel.vercel.app/s/abc12345#key=..." --output - > .env

Output

output
Fetching...
Decrypting locally...

✓ Written to .env

⚑ Token consumed. Secret permanently deleted.

#Configuration

The CLI talks to the SecretTunnel web API. You can point it at a self-hosted instance via environment variables.

Environment variables

VariableDescription
SECRETTUNNEL_API_URLHighest priority. Overrides the API base URL completely.
API_URLFallback if SECRETTUNNEL_API_URL is not set.
NODE_ENVIf production and no URL env vars are set, defaults to https://secrettunnel.vercel.app/api/secrets.

Resolution priority:

  1. SECRETTUNNEL_API_URL (highest priority)
  2. API_URL
  3. NODE_ENV=production https://secrettunnel.vercel.app/api/secrets
  4. Default: http://localhost:3000/api/secrets
shell
export SECRETTUNNEL_API_URL="https://your-self-hosted-instance.com"

#Error handling

The CLI exits with a non-zero code on failure. Common errors and how to resolve them:

Missing key.

Cause — You passed a URL without the #key=… fragment, or forgot --key.

Fix — Use the full share URL including the hash, or pass --key explicitly.

Secret not found.

Cause — The secret was already consumed by a previous pull, or its TTL expired.

Fix — Ask the sender to create a new secret.

Failed to decrypt secret / Incorrect password or corrupted key.

Cause — Wrong password, or the key hash was truncated during copy-paste.

Fix — Double-check the password and ensure the full URL was copied.

Unknown option ...

Cause — A flag was passed to the wrong command (e.g., --ttl on pull).

Fix — Flags are validated per-command. Check the signature above.

#Core behaviors

🔥

Burn after read

Secrets are permanently destroyed once successfully retrieved. Running pull a second time will fail.

🔒

Client-side encryption

The server stores only ciphertext and IV. It never receives your key. The key travels strictly via the URL hash.

🔑

Strict decryption

pull requires both the token and the decryption key. Without the exact key, recovery is mathematically impossible.

📁

File overwrite protection

When --output points to an existing file, the CLI prompts for confirmation before overwriting.