What is this?
Remember in spy movies when someone leaves a briefcase under a park bench, and someone else picks it up later? That's a dead drop.
This is that, but for files. And the briefcase is encrypted with military-grade cryptography. And the park bench self-destructs after pickup. And nobody β not even the bench β knows what's inside. And now the bench can hide on the dark web. π§
βββββββββββ βββββββββββ
β You β β Friend β
ββββββ¬βββββ ββββββ¬βββββ
β β
β ded ./secret-plans.pdf β
β βββββββββββββββββββββββ β
β β
ββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β π Your Machine ββ
β ββββββββββββ ββββββββββββββββ ββββββββββββββββ ββ
β β Encrypt βββββΊβ Ciphertext βββββΊβ HTTP Server β ββ
β β (Rust) β β (on disk) β β (Axum) β ββ
β ββββββββββββ ββββββββββββββββ ββββββββ¬ββββββββ ββ
β π Key goes in URL #fragment β ββ
βββββββββββββββββββββββββββββββββββββββββββββββΌββββββββββββ
β β β
β π² Sends link via Signal / QR scan β β
β β β β β β β β β β β β β β β β β β ββΊβ β
β β β
β βββββββ΄ββββββββ β
β β Opens URL βββββ
β β in browser β
β βββββββ¬ββββββββ
β β
β βββββββββββββββ΄ββββββββββββββ
β β π¦ Browser fetches blob β
β β π Extracts #key β
β β β‘ WASM decrypts locally β
β β πΎ File downloads β
β βββββββββββββββ¬ββββββββββββββ
β β
ββββββ΄βββββββββββββββββββββββββββββββ β
β π₯ Self-destruct triggered β β
β π₯ Drop marked as burned β β
β π Server shuts down β β
βββββββββββββββββββββββββββββββββββββ β
β β
βΌ βΌ
What file? There was no file. Got it. Thanks. π
Features
Core β the stuff that makes your IT department nervous
| Feature | Description |
|---|---|
| π Endβtoβend encrypted | XChaCha20βPoly1305. The server never sees the key. Like a blind courier. |
| π Key in URL fragment | The #key part never hits server logs, proxies, or HTTP headers. It's a ghost. |
| π₯ Selfβdestruct | Expire by time, by download count, or both. This message will selfβdestruct in... |
| π± Works on phones | Receiver only needs a browser. No app. No account. No soulβselling signup. |
| π Send folders | Directories autoβpack to .tar.gz. Your entire homework/ folder, encrypted. π |
| π¦ Multiβfile drops | ded file1.txt file2.pdf photos/ β bundles everything into one encrypted drop. |
| π Stdin / clipboard | echo "secret" | ded - β pipe anything. Your terminal is the dead drop. |
| βΎοΈ Unlimited file size | Streams from disk β your 50GB file won't eat your RAM for breakfast. |
| π Password protection | Argon2id key derivation (64MB memoryβhard, GPUβresistant). Receiver gets a password prompt in-browser β key is derived client-side. The server never sees the password OR the key. Fort Knox mode. π° |
| π² QR code | Because typing URLs is for people who still use fax machines. |
| π₯ Receive mode | ded receive β phoneβtoβPC uploads. Your phone becomes the dead drop. |
| π§ Tor hidden service | --tor β generates a .onion address. The dark web called, it wants its files. |
| π¦ Single binary | No runtime, no Docker, no config files. Just one executable. Like a katana. π‘οΈ |
Security Hardening β because paranoia is a feature
| Feature | Description |
|---|---|
| π» Fragment autoβclear | #key is stripped from the URL bar and history the instant the page loads. Poof. |
| π IP pinning | Download is locked to the first IP that connects β everyone else gets a 403 slap. |
| π‘ Security headers | CSP, X-Frame-Options: DENY, no-referrer, no-cache. The whole paranoia buffet. |
| β± Rate limiting | 2 req/sec per IP with burst of 5 β stops bruteβforce nerds in their tracks. |
| π― 16βchar drop IDs | ~2βΆβ΄ possible IDs β you'll win the lottery before guessing one. |
| π Constantβtime 404s | Random delay on not-found β prevents timingβbased detective work. |
| π₯ Burn page | Late visitors see "π₯ This drop was already downloaded and destroyed." Savage. |
| β° Autoβexpire page | Tab stays open past expiry? Key nuked from JS memory. The UI selfβdestructs. |
| π§ Memory locking | mlock() on Unix prevents the key from being swapped to disk. It lives in RAM or dies. |
| π Zeroβwrite deletion | Encrypted temp files get overwritten with zeros before rm. CSI can't touch this. |
| π§Ή Key zeroization | Key wiped from RAM (via zeroize) on drop, both server and browser. Clean exit. |
Installation
π One-line install (Linux/macOS)
|
Detects your OS & architecture automatically, downloads the right binary, and adds it to your PATH. Magic.
Download a binary
Grab the latest release for your platform from Releases.
| Platform | Binary | Architecture |
|---|---|---|
| Windows | ded-windows-x86_64.exe |
x86_64 |
| Linux | ded-linux-x86_64 |
x86_64 (musl, static) |
| Linux | ded-linux-aarch64 |
ARM64 (Raspberry Pi, etc.) |
| macOS | ded-macos-x86_64 |
Intel |
| macOS | ded-macos-aarch64 |
Apple Silicon (M1/M2/M3/M4) |
Quick install (Linux/macOS):
# Linux x86_64
&& &&
# macOS Apple Silicon
&& &&
Via cargo
Build from source (for the trustβnoβone crowd)
# Binary at: target/release/ded
π Update
# Linux/macOS β same as install, overwrites the old binary
|
# Via cargo
π Uninstall
# If installed via script
&&
# If installed to /usr/local/bin/
&&
# If installed via cargo
Usage
The basics β impress your friends in 3 seconds
# Send a file β that's it, that's the whole tool
# Send a folder β auto-archives to .tar.gz
# Send multiple files β bundles into one drop
# Pipe from stdin β your clipboard is a dead drop
|
|
Receive mode β your phone becomes the dead drop
# Open upload page on your LAN β scan QR from phone
# Save to a specific folder
# Custom port, no QR
Scan the QR from your phone β pick a file β encrypted in-browser β sent to your PC β decrypted β saved. One upload, then π₯ server self-destructs.
Password mode β true zeroβknowledge π
# Share a file with a password
How it works:
- Server encrypts the file with a key derived from your password via Argon2id (64MB, 3 iterations)
- The URL contains the salt (not the key) β so the link alone can't decrypt anything
- Receiver opens the link β sees a π password prompt β enters the password
- Browser derives the same key via Argon2id in WASM (same params, runs client-side)
- File decrypts locally. Server never sees the password or the key. Ever.
π‘ Pro tip: Send the link over Slack, tell them the password on a phone call. Two channels = maximum paranoia.
The spicy options πΆοΈ
# Self-destruct after 1 download, expire in 10 minutes
# 30-second self-destruct. Blink and it's gone.
# Go full Mission Impossible
# Go full dark web spy π΅οΈ
# Receive via Tor β your phone uploads through the shadow realm
What you see
βββββββ ββββββββ ββββββ βββββββ βββββββ βββββββ βββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
βββ βββββββββ βββββββββββ ββββββββββββββ βββββββββββ
βββ βββββββββ βββββββββββ ββββββββββββββ ββββββββββ
βββββββββββββββββββ ββββββββββββββ βββββββββββββββ
βββββββ βββββββββββ ββββββββββ βββ βββ βββββββ βββ
β‘ zero-knowledge encrypted file sharing β‘
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
β URL http://192.168.1.42:8080/d/a3f9c1b2#xK9m β
β β
β ββ File secret.pdf β
β ββ Size 4.2 MB β
β ββ Expires 10m β
β ββ Downloads 1 β
β ββ π Password yes (Argon2id) β
β ββ Crypto XChaCha20-Poly1305 β
ββββββββββββββββββββββββββββββββββββββββββββββββββββ
π§
Tor: http://abc...xyz.onion/d/a3f9c1b2#pw:... β (with --tor)
βββββββ ββββββ βββββββ <- QR code appears here
β βββ β βββ ββ β βββ β scan with phone π±
...
What the receiver sees (password-protected drop)
ββββββββββββββββββββββββββββββββββββββββββββ
β DEADROP encrypted dead drop β
β β
β π File secret.pdf β
β π¦ Size 4.2 MB β
β β° Expires 59m β
β π Encryption XChaCha20-Poly1305 β
β β
β π This drop requires a password β
β ββββββββββββββββββββββββββββββββββββ β
β β Enter password... ββ β
β ββββββββββββββββββββββββββββββββββββ β
β β
β [ π Unlock & Download ] β
ββββββββββββββββββββββββββββββββββββββββββββ
After entering the correct password, Argon2id runs in WASM (~2-5 seconds on the derivation), then the file decrypts and downloads. Wrong password? Decryption fails gracefully β try again.
π Demo Commands β Try Every Feature
Run one at a time β each starts a server. Ctrl+C to stop, then run the next.
| # | Feature | Command | What happens |
|---|---|---|---|
| 1 | π Single file | ded secret.pdf |
Encrypts β serves link β browser decrypts β π₯ |
| 2 | π Folder | ded ./my-folder/ |
Archives β encrypts β serves .tar.gz |
| 3 | π¦ Multi-file | ded file1.txt file2.pdf pics/ |
Bundles all β one encrypted archive |
| 4 | π Stdin pipe | echo "swordfish" | ded - |
Reads stdin β drops as clipboard.txt |
| 5 | β± Custom expiry | ded file.txt -e 5m |
Auto-expires after 5 minutes |
| 6 | π’ Download limit | ded file.txt -n 3 |
Self-destructs after 3 downloads |
| 7 | π« No QR | ded file.txt --no-qr |
URL only, no QR code (you hate fun) |
| 8 | π Password | ded file.txt --pw "hunter2" |
Receiver gets password prompt. Argon2id in-browser. |
| 9 | π Custom port | ded file.txt -p 9090 |
Listens on port 9090 |
| 10 | π€― Full paranoia | ded file.txt -n 1 -e 30s --pw "yolo" |
1 download, 30s, password. Gone. |
| 11 | π₯ Receive mode | ded receive -o ~/Downloads/ |
Upload page β phone sends file to PC |
| 12 | π₯π§ Receive custom | ded receive -p 9999 --no-qr |
Custom port receive, no QR |
| 13 | π§ Tor send | ded secret.pdf --tor |
Generates .onion URL. Dark web drop. |
| 14 | π§ π₯ Tor receive | ded receive --tor -o ~/secrets/ |
Tor receive. Max stealth. |
| 15 | π IP pinning test | ded file.txt -n 2 |
Download on PC β try on phone β 403 blocked |
| 16 | β° Auto-expiry test | ded file.txt -e 30s |
Wait 30s β open URL β "Drop not found" |
β‘ Flags Cheat Sheet
ded [send] β Send mode (the default)
sendis optional βded file.txtandded send file.txtare identical.
| Flag | Short | Default | What it does | Vibe |
|---|---|---|---|---|
<PATH>... |
β | β | File(s), folder(s), or - for stdin |
π― The stuff you're dropping |
--port |
-p |
8080 |
Port to listen on | πͺ Pick your door |
--expire |
-e |
1h |
Autoβexpire duration (30s, 10m, 1h, 7d) |
β° The countdown timer |
--downloads |
-n |
1 |
Max downloads before selfβdestruct (0 = β) | π£ How many pickups |
--pw |
β | None | Password-protect drop (Argon2id, 64MB memoryβhard). Receiver gets a password prompt in-browser. | π° Fort Knox mode |
--bind |
-b |
0.0.0.0 |
Bind address | π Which interface |
--no-qr |
β | false |
Suppress QR code | π You hate fun |
--tor |
β | false |
Enable Tor hidden service | π§ Dark web activated |
ded receive β Receive mode
| Flag | Short | Default | What it does | Vibe |
|---|---|---|---|---|
--port |
-p |
8080 |
Port to listen on | πͺ Pick your door |
--output |
-o |
. |
Save received files here | π Where the loot goes |
--bind |
-b |
0.0.0.0 |
Bind address | π Which interface |
--no-qr |
β | false |
Suppress QR code | π Still no fun |
--tor |
β | false |
Enable Tor hidden service | π§ Receive from the shadow realm |
How It Works
Send flow
ββββββββββββ ββββββββββββββββββββββ ββββββββββββ
β Sender β β Server (your PC) β β Receiver β
βββββββ¬βββββ βββββββββββ¬βββββββββββ βββββββ¬βββββ
β β β
β 1. Generate random β β
β 256-bit key β β
β (or derive from pw) β β
β β β
β 2. Encrypt file β β
β XChaCha20-Poly1305 β β
β β β
β 3. Store ciphertext βββΊβ β
β β β
β 4. Key β URL #fragment β β
β (or salt if --pw) β β
β β β
β 5. Share link β β β β βββ β β β β β β β β β β ββΊβ
β (Signal, QR, etc.) β β
β β β
β ββββ 6. Open link βββββββββββ
β β β
β ββββ 7. Serve encrypted βββΊβ
β β blob (HTTP) β
β β β
β β 8. Browser extracts β
β β #key (or prompts β
β β for password) β
β β β
β β 9. WASM decrypts β
β β locally in browser β
β β β
β β 10. File downloads β
β β to device β
β β β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β π₯ Self-destruct β π₯ Burned β π Off β β
β βββββββββββββββββββββββββββββββββββββββββββ β
βΌ βΌ
Password flow (zero-knowledge)
ββββββββββββ ββββββββββββββββββββββ ββββββββββββ
β Sender β β Server (your PC) β β Receiver β
βββββββ¬βββββ βββββββββββ¬βββββββββββ βββββββ¬βββββ
β β β
β ded file --pw "pass" β β
β β β
β 1. Argon2id(pass,salt) β β
β β 256-bit key β β
β β β
β 2. Encrypt with key β β
β 3. URL = #pw:<salt> β β
β (NOT the key!) β β
β β β
β 5. Share link β β β β βββ β β β β β β β β β β ββΊβ
β 6. Tell password β β βββ β β β (phone call) β ββΊβ
β β β
β ββββ 7. Open link βββββββββββ
β β β
β β 8. Browser shows π β
β β password prompt β
β β β
β β 9. Receiver types pw β
β β 10. WASM: Argon2id β
β β (pw,salt) β key β
β β β
β ββββ11. Fetch blob ββββββββββ
β ββββΊ12. Return ciphertextβββΊβ
β β β
β β 13. WASM decrypts β
β β 14. File downloads β
β β β
β ββββββββββββββββββββββββββββββββββββββββ β
β β Server never saw: password or key β β
β ββββββββββββββββββββββββββββββββββββββββ β
βΌ βΌ
Receive flow
ββββββββββββ ββββββββββββββββββββββ ββββββββββββ
β Receiver β β Server (your PC) β β Phone β
β (PC) β β β β (sender) β
βββββββ¬βββββ βββββββββββ¬βββββββββββ βββββββ¬βββββ
β β β
β ded receive β β
β ββββββββββββ β β
β β β
β 1. Generate key βββββββΊβ β
β 2. Key β QR code β β
β β β
β ββββ 3. Scan QR, open ββββββ
β β upload page β
β β β
β β 4. Pick file β
β β 5. WASM encrypts β
β β in-browser β
β β β
β ββββ 6. Upload ciphertext ββ
β β β
β 7. Server decrypts ββββ β
β 8. Saves to disk β β
β β β
β ββββββββββββββββββββββββββββββββββββββββ β
β β β
Saved β π₯ Self-destruct β π Off β β
β ββββββββββββββββββββββββββββββββββββββββ β
βΌ βΌ
The critical insight: the #fragment in a URL is never sent to the server. Not in HTTP requests, not in logs, not in referrer headers. The server literally cannot learn the key even if it wanted to. It's like trying to read a letter through a sealed envelope. While blindfolded. In the dark.
Tor flow π§
ββββββββββββ βββββββββββββββ ββββββββββββββββ ββββββββββββ
β Sender ββββββΊβ ded --tor ββββββΊβ Tor Network ββββββΊβ Receiver β
β β β β β (.onion) β β (Tor β
β β β Generates β β β β Browser)β
β β β .onion URL β β 3 relays β β β
ββββββββββββ βββββββββββββββ ββββββββββββββββ ββββββββββββ
β
No IP. No trace. β
Just encrypted bytes. β
βΌ
File decrypts
in browser π
Security Architecture
Defense in Depth
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Layer 7 β Self-destruct One download β burn β server off β
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 6 β Browser Fragment auto-clear + auto-expire β
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 5 β Anti-forensics mlock() + zeroize + zero-write β
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 4 β Access control IP pinning + rate limit + 64-bit IDβ
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 3 β Network HTTP + security headers β
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 2 β Zero-knowledge Key in URL #fragment only β
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 1 β Encryption XChaCha20-Poly1305 (256-bit, AEAD) β
β βββββββββββͺβββββββββββββββββββββββββββββββββββββββββββββββββββββββ£
β Layer 0 β Anonymity Tor hidden service (.onion) π§
β
ββββββββββββ§βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Threat Model
β Protected against
| Threat | How |
|---|---|
| Server operator learning file contents | Zeroβknowledge β key never reaches server |
| Manβinβtheβmiddle reading the key | Key lives in #fragment, never transmitted over HTTP |
Someone intercepting the URL (with --pw) |
URL contains salt, not key. They still need the password. |
| Network eavesdropping | Encryption at application layer (XChaCha20-Poly1305) |
| Server logs leaking the key | Fragments aren't logged by any HTTP server or proxy |
| Brute force on encryption | XChaCha20-Poly1305 with 256βbit keys. See you in 10Β²β° years. |
| GPU attacks on passwords | Argon2id with 64MB memory cost. Your 4090 weeps. |
| Drop ID enumeration | 16βchar IDs (~2βΆβ΄) + rate limiting + constantβtime 404s |
| URL bar shoulder surfing | Fragment stripped from URL bar on page load |
| Browser history forensics | history.replaceState() removes the #key |
| Key persisting in RAM | zeroize on Rust side, key = null on JS side |
| Key swapped to disk (Unix) | mlock() pins key memory pages |
| Encrypted file recovery | Zeroβoverwrite before deletion |
| Clickjacking / iframe embedding | X-Frame-Options: DENY + frame-ancestors 'none' |
| XSS injection | Content Security Policy β scripts only from 'self' |
| Stale tab leaking key | Autoβexpire nukes key from memory when drop expires |
| IP tracking | --tor hides both sender and receiver behind .onion |
| Late visitor confusion | Burn page β "already downloaded and destroyed" |
β NOT protected against
- Someone who has the full URL with the
#key(for non-password drops, that IS the key β guard it) - Malware on sender/receiver device (keyloggers, screen capture)
- Your friend screenshotting the file and posting it on Twitter
- Rubber hose cryptanalysis (look it up, it's not pretty π¨)
- Time travelers
- Your mom looking over your shoulder
- The NSA (just kidding... unless? π)
Technical Details
| Component | Choice | Why |
|---|---|---|
| Encryption | XChaCha20βPoly1305 | 256βbit, extended nonce, AEAD. Used by WireGuard, Cloudflare |
| KDF | Argon2id | Memoryβhard, GPUβresistant. 64MB cost, 3 iterations. Winner of Password Hashing Competition |
| Browser KDF | Argon2id (WASM) | Same Rust argon2 crate compiled to WASM β identical params, runs client-side |
| Chunk size | 64KB | Balances streaming performance vs. auth tag overhead |
| Server | Axum (Rust) | Async, zero-copy, no garbage collector. Blazingly fastβ’ |
| Rate limiter | tower_governor | Token bucket per IP β stops brute force |
| Browser crypto | WebAssembly | Same Rust code compiled to WASM, near-native speed |
| Nonce derivation | base XOR chunk_index | Per-chunk unique nonces without storing them |
| Binary embedding | rust-embed | HTML, CSS, JS, WASM all baked into the single binary |
| Memory safety | mlock + zeroize | Key never hits swap, wiped from RAM on drop |
| Anonymity | Tor hidden service | .onion address via local tor daemon |
| Archive | tar + flate2 | Folder/multi-file bundling with gzip compression |
Memory Usage
| File Size | Server RAM | Browser RAM | Notes |
|---|---|---|---|
| 1 MB | ~5 MB | ~5 MB | Smol file, smol memory |
| 100 MB | ~5 MB | ~200 MB | Still chill |
| 1 GB | ~5 MB | ~2 GB | Desktop territory |
| 10 GB | ~5 MB | Desktop only | Streaming mode. Server doesn't care. |
The server uses constant memory regardless of file size. It streams encrypted chunks from disk. Your 50GB Linux ISO is treated the same as a 1KB text file (memory-wise).
FAQ
Q: Is this legal? A: It's a file sharing tool with encryption. Like Signal, or HTTPS, or putting a letter in an envelope. What you put inside is your business.
Q: Can I use this at work? A: Your IT department will either promote you or fire you. No in-between.
Q: Why not just use Google Drive? A: Google Drive knows your files. Deadrop doesn't. That's the whole point. Also Google Drive doesn't self-destruct. Boring.
Q: What happens if I lose the URL? A: The file is gone. That's... the feature. It's a dead drop, not Google Photos.
Q: Can the server see my files? A: No. The encryption key is in the URL fragment which never reaches the server. The server holds meaningless encrypted bytes. It's like asking if your mailbox can read your letters.
Q: What about password-protected drops? A: Even better. The URL only has the salt β the server never sees the password or the key. The receiver's browser derives the key locally via Argon2id in WASM. True zero-knowledge. The server is literally clueless.
Q: What if someone intercepts my password drop URL? A: Without the password, the URL is useless. It only contains a random salt. They'd need to brute-force Argon2id (64MB memory Γ 3 iterations per guess). Good luck with that.
Q: What if someone else tries the link? A: They can't. IP pinning locks the download to the first device. Second IP gets 403'd into oblivion.
Q: What if I visit a dead link? A: Already downloaded β "π₯ This drop was already downloaded and destroyed." Expired β "Drop not found." Either way, it's gone. Like your ex's texts.
Q: Why does --tor take so long?
A: Tor needs ~30-60 seconds to generate a .onion address and establish circuits through 3 relays. Patience. Good anonymity takes time.
Q: Can I send multiple files?
A: Yes! ded file1.txt file2.pdf folder/ bundles everything into one encrypted .tar.gz archive automatically.
Q: Can I pipe from stdin?
A: echo "the password is swordfish" | ded - β works like a charm. Serves it as clipboard.txt.
Q: Why Rust? A: Because we wanted the binary to be fast, safe, and have zero runtime dependencies. Also because we enjoy fighting the borrow checker at 3 AM. It builds character.
Contributing
PRs welcome. Here's the roadmap:
-
End-to-end encryption (XChaCha20-Poly1305) -
QR code generation -
Self-destruct by time & download count -
IP pinning -
Folder support (.tar.gz) -
ded receivemode (phone β PC) -
Multi-file drops -
Stdin / clipboard mode -
Tor hidden service -
Password protection (Argon2id) -
In-browser password prompt with client-side Argon2id - Receiverβside streaming decryption for huge files on mobile
- Web UI drag-and-drop improvements
- Resume interrupted downloads
- Multi-recipient drops (different keys per recipient)
Star History
If you've read this far, you're legally obligated to star the repo. It's in the fine print.
β Star this repo β it makes the self-destruct mechanism work better. (Not really, but it makes us happy.)
License
MIT β do whatever you want. Just don't blame us if your dead drop gets intercepted by actual spies. Or if your friend screenshots the file. Or if time travelers get involved.