send-secret
v0.3.2
Published
P2P encrypted secret sharing. No servers. No accounts. No trust required. VS Code extension available.
Maintainers
Readme
The Problem
Every day, developers share API keys, database credentials, and secrets through:
- Slack DMs — stored forever on Slack's servers
- Email — sitting in inboxes indefinitely
- Text messages — backed up to iCloud, Google, carrier logs
- Notion/Docs — accessible to anyone with the link
.envfiles in repos — we've all seen it
These secrets persist. They get indexed. They get breached.
The Solution
send-secret creates a one-time, encrypted link that self-destructs after viewing.
$ echo "sk_live_abc123" | npx send-secret- Zero trust — Your machine encrypts the secret. The key never leaves the URL fragment.
- Zero persistence — Deleted from memory the moment it's viewed. Nothing stored anywhere.
- Zero accounts — No signups, no logins, no third-party services holding your secrets.
- Zero install — Works with
npx. No dependencies to audit.
Install
npm i -g send-secretOr use without installing:
npx send-secretVS Code Extension
Share secrets directly from your editor:
ext install danwag06.send-secretOr search "send-secret" in the VS Code extensions marketplace.
Right-click any file or selection → Send Secret → link copied to clipboard.
AI Coding Agents
Use send-secret with Claude Code, Cursor, Codex, and other AI coding agents.
Install Skills
npx add-skill danwag06/send-secretThis installs skills that let AI agents help you share secrets without the agent ever seeing the secret content:
| Skill | Description |
|-------|-------------|
| send-secret-file | Send files by path (agent never reads content) |
| receive-secret | Receive secrets to files (saves with -o, never displays) |
| send-secret-clipboard | Share clipboard contents (macOS - agent never sees clipboard) |
Security Model
The skills are designed so secrets never enter the agent's context:
- Files are sent by path only — agent runs
send-secret ./file.jsonwithout reading the file - Secrets are received to files — agent always uses
-oflag to save, never displays in terminal - Clipboard is piped directly —
pbpaste | send-secretbypasses agent context entirely
Example Usage
Ask your AI agent:
- "Send my .env file securely to my teammate"
- "Receive this secret: https://xyz.trycloudflare.com/s/abc#key=..."
- "Share what I copied to my clipboard securely"
Usage
Send a text secret
$ send-secret
Enter secret, press Enter, then Ctrl+D:
sk_live_abc123xyz
^D
○ Encrypting (18 B)
✔ Tunnel ready
╭ Share this link ─────────────────────────────────────────────────────────────╮
│ https://abc123.trycloudflare.com/s/x7k2m#key=9f86d081884c7d659a2feaa0c │
╰──────────────────────────────────────────────────────────────────────────────╯
Keep terminal open until received
Recipient can also run: npx send-secret -r <link>
◐ Waiting for receiver...
✔ Retrieved from 73.162.45.99Send a file
$ send-secret ./credentials.json
○ Encrypting credentials.json (4.2 KB)
✔ Tunnel ready
╭ Share this link ─────────────────────────────────────────────────────────────╮
│ https://abc123.trycloudflare.com/s/x7k2m#key=9f86d081884c7d659a2feaa0c │
╰──────────────────────────────────────────────────────────────────────────────╯
Keep terminal open until received
Recipient can also run: npx send-secret -r <link>
◐ Waiting for receiver...
✔ Retrieved from 73.162.45.99Send via pipe
$ cat .env | send-secret
$ echo "secret_token" | send-secret
$ pbpaste | send-secretAuto-destruct timeout
Set an expiration time for undelivered secrets:
$ send-secret -t 300 ./secret.txt # Expires in 5 minutes
$ send-secret --timeout 60 # Expires in 60 seconds
◐ Waiting for receiver... (expires in 4m 32s)If the receiver doesn't retrieve the secret before the timeout, it's automatically deleted.
Multiple recipients
Share with multiple people using a single link:
$ send-secret -n 3 ./credentials.json # Allow 3 views
$ send-secret -n 5 -t 300 ./secret.txt # 5 views OR 5 minutes
◐ Waiting for receivers... (0/3)
✔ Retrieved (1/3) from 73.162.45.99
✔ Retrieved (2/3) from 98.45.123.12
✔ Retrieved (3/3) from 73.162.45.99 — All deliveredThe sender sees each retrieval with the IP address for visibility.
Receive via CLI
Receivers can open the link in a browser, or use the CLI:
$ send-secret -r <url>
# or
$ send-secret receive <url>
◐ Fetching secret...
✔ Secret retrieved
╭─────────────────────╮
│ sk_live_abc123xyz │
╰─────────────────────╯Files are automatically saved with timestamps to prevent overwrites:
$ send-secret receive <url>
◐ Fetching secret...
✔ Secret retrieved
✔ File saved. View with:
cat "/Users/you/.send-secret/received/credentials_2025-01-14T10-30-45.json"Use -o to specify where to save:
$ send-secret -r <url> -o ./ # Save to current dir with original filename
$ send-secret -r <url> -o ./secrets/ # Save to specific directory
$ send-secret -r <url> -o ./myfile.json # Save with custom filenameHow It Works
Sender Receiver
│ │
├─ Encrypt secret locally │
├─ Start local server │
├─ Open Cloudflare tunnel │
├─ Generate URL with key │
│ in fragment │
│ │
├─────── Share URL ────────────▶│
│ │
│◀─────── Receiver opens URL ───┤
│ │
├─ Serve HTML + encrypted blob │
│ ├─ Decrypt in browser
│ ├─ Display secret
├─ Delete blob from memory │
├─ Close tunnel │
├─ Exit │
│ │
▼ ▼
Done DoneThe decryption key lives in the URL fragment (#key=...), which is never sent to any server — not even Cloudflare. Only someone with the full URL can decrypt the secret.
Security
| Threat | Protected | How | | ------------------ | --------- | ------------------------------------------------- | | Server sees secret | ✓ | Encrypted before leaving sender's machine | | Man-in-the-middle | ✓ | Decryption key in URL fragment, never transmitted | | Secret persists | ✓ | Deleted from memory immediately after viewing | | Sender's disk | ✓ | Never written to disk, only held in memory | | Brute force | ✓ | AES-256-GCM with 256-bit key (2²⁵⁶ possibilities) |
What's NOT Protected
- Link interception — If someone gets the full URL, they can view the secret
- Receiver's machine — Once decrypted, it's in their browser/terminal
- Metadata — Cloudflare sees IPs, timing, and payload size (but not content)
Encryption Details
- Algorithm: AES-256-GCM (authenticated encryption)
- Key: 256-bit cryptographically random
- IV: 96-bit random per encryption
- Key transmission: URL fragment only (never sent to server)
Requirements
- Node.js 18+
- Internet connection (for Cloudflare tunnel)
License
Apache-2.0
Support
If send-secret saves you time, consider supporting development:
Crypto:
| Currency | Address |
| -------- | ---------------------------------------------- |
| BTC | bc1qgel38lkck8vk4hpqjlzhjwg8rv39auahqxz7mg |
| ETH | 0x8e9CeeaeF8beC7dfCa6D02B1c83f341217AA82F5 |
| SOL | FsT8cZ6naBc7vAmqt3bEzKreLgAHT9HaWrmC32wvii15 |
| BCH | qpykcppaaazfkt5dd3n6stswnxn4ehyxxc8m0z43v3 |
| BSV | 1QFxtdewusnJsgyWWLviiZKEsDSsb77HPN |
