๐Ÿ”ย  Zero-knowledge ยท AES-256-GCM ยท Burn after read

Share secrets.
Not exposure.

Encrypted in your browser. Stored as ciphertext. Destroyed on read.
The server is provably blind.

terminal
$

// How it works

Four layers. Zero trust.

01
lock

You encrypt, locally

AES-256-GCM runs entirely in your browser using the Web Crypto API. The plaintext never leaves your device unencrypted.

await crypto.subtle.encrypt(
{ name: "AES-GCM", iv }, key, data
)
02
link

Key stays in URL fragment

The decryption key is appended as a #fragment โ€” which browsers never include in HTTP requests. The server receives zero key material.

https://secrettunnel.app/s/token#key=aB3dK9...
[โ”€โ”€โ”€ sent to server โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€][โ”€ never sent โ”€]
03
database

Server stores only ciphertext

Redis holds { ciphertext, iv, ttl }. Nothing else. Even a full server breach leaks only encrypted bytes.

04
local_fire_department

Burn on read

The moment the recipient decrypts, the Redis key is atomically deleted. The link is dead. No replay, no second access.

// CLI

Push and pull from anywhere.

No browser required. One command to share, one to receive. Built for CI pipelines, onboarding scripts, and developers who live in the terminal.

โ†’Push your .env with npx secrettnl push
โ†’Pull directly to a file โ€” never touches clipboard
โ†’Password-protect for extra layer
โ†’Set TTL from seconds to days
โ†’Add webhook callbacks for access events
terminal
$npx secrettnl push--file .env--ttl 24h --webhook https://hooks.you.com/notify
โœ“ Secret created
https://secrettunnel.app/s/x9k2m#key=aB3dK9...
โš‘ Burn-after-read ยท Expires in 24h
terminal
$npx secrettnl pull"https://secrettunnel.app/s/x9k2m#key=aB3dK9..."--output .env
Fetching...
Decrypting locally...
โœ“ Written to .env
โš‘ Token consumed. Secret permanently deleted.
Full CLI reference โ†’

// Features

Everything you need.
Nothing you don't.

password

Password Protection

Add a PBKDF2-derived second encryption layer. Even with the link, wrong password = no access.

timer

Configurable TTL

Set expiry from 30s to 7d. Redis auto-deletes. 1h, 24h, 7d or raw seconds.

webhook

Webhook on View

Attach a webhook URL. Get an HTTP POST the moment your secret is accessed. Powered by QStash.

history

Versioned Secrets

Group secrets into named vaults with version history. Diff any two versions.

shield_person

Audit Trail

View timestamp and viewer IP logged per access. Stored in Redis, separated from the secret.

passkey

GitHub OAuth

Sign in to manage your secret history, audit logs, and versioned vaults from the dashboard.

// Versioned Secrets

Track changes. Securely.

Manage configuration drift across your team.

Group secrets into named vaults. Every time you push a new version, a diff is computed and stored. Roll back instantly.

diff editor
12DATABASE_URL="postgresql://..."
13- API_KEY="sk_old_8f29d2k..."
14+ API_KEY="sk_new_931ms0q..."
15NEXT_PUBLIC_URL="https://..."
Version:
v1v2v3 (current)

// Security Model

Threat mitigations.

ThreatMitigation
Server compromiseOnly ciphertext stored. Key never transmitted.
Link interceptionKey in #fragment โ€” never in HTTP requests or logs.
Replay attacksBurn-after-read โ€” deleted on first GET.
Brute forceSliding window rate limiting: 10 secrets/hr per IP.
Weak passwordsOptional PBKDF2 key stretching.
Stale secretsMandatory TTL โ€” Redis auto-expires.

One command.
Your secrets, gone forever.

Start in 10 seconds.

$npx secrettnl push"hello team"--ttl 1h