B1 Drop

Security model

What B1 Drop protects, and what it doesn’t

B1 Drop is built so that the server holds only data it can’t read, and holds it briefly. This page explains how it works and where the limits are.

How a drop is sealed

browser                                   b1.gg (our server + database)
───────                                   ─────────────────────────────
key  = 32 random bytes  (crypto.getRandomValues)
salt = 16 random bytes, iv = 12 random bytes
[passphrase?]  p = PBKDF2-SHA256(passphrase, salt, 600 000)
aes  = HKDF-SHA256(key [|| p], salt, "b1-drop/v1")
ct   = AES-256-GCM(aes, iv, data, aad = header)
            ── POST header || ct ──────►  stores ciphertext only, with an expiry
            ◄── id (8 chars) ──────────
link = https://b1.gg/<id>#<key>

Browsers don’t send the part of a URL after # (the fragment) in HTTP requests. So the key never reaches B1 Drop’s servers, our hosting provider, or any server logs. Short ids are 8 random base-62 characters, about 47.6 bits. Lookups are rate-limited per network.

How a drop is opened

Opening the link loads a page that only checks whether the drop exists. It doesn’t touch the ciphertext. When you press Reveal and delete, your browser sends a POST, and the server runs DELETE … RETURNING on the drop as one atomic operation in our database. If two requests race, exactly one of them gets the data. Everyone else gets “gone”. The browser then decrypts the data locally and removes the key from the address bar.

Link previews

Slack, iMessage, Teams, WhatsApp and email scanners often fetch links to build previews. Their fetch is a GET, and a GET never consumes a drop. Revealing needs a POST with a custom header, which a preview bot doesn’t send and which other websites can’t send cross-origin without a CORS preflight that B1 Drop never approves. The preview card shows a generic title, never the contents.

Passphrases

A passphrase is an optional second factor. Someone who has the link but not the passphrase can still burn the drop by revealing it, but they can’t read it. If you type a wrong passphrase, the drop has already been deleted from the server. It stays in that browser tab so you can try again, and it’s lost when you close the tab. PBKDF2 slows down guessing, but a weak passphrase can still be guessed offline by anyone who has both the link and the ciphertext.

What B1 Drop does not protect against

  • Anyone who gets the full link first. The link is the key. If it leaks (chat history, email, a screenshot, a shared clipboard), whoever opens it first reads it. You will see “gone” and know something is wrong, but you can’t undo it.
  • A compromised device on either end, malicious browser extensions, or the recipient keeping a copy.
  • A compromised server delivering malicious JavaScript. As with every web-based encryption tool, you trust the code b1.gg serves at the time you use it. We use a strict Content-Security-Policy and no third-party scripts, but that doesn’t remove this trust.
  • Metadata. Our hosting provider handles your IP address and the request times in order to serve the site. B1 Drop stores the ciphertext size, its creation and expiry times, and a salted hash of your network for rate limiting.
  • Proof of who sent it. Drops are anonymous. Confirm the sender through another channel.

Deletion and expiry

A revealed drop is deleted immediately. An unopened drop is refused once its expiry passes, and a scheduled job deletes it within the hour. Our database keeps encrypted point-in-time recovery snapshots for about 7 days (longer on a paid plan). This is a feature of the database platform, controlled by the operator. Any copy there is ciphertext without the key.

Limits

ItemLimit
File or message size5 MB
Expiry options1 hour, 1 day, 7 days
New drops20 per hour per network
Lookups and reveals30 per minute per network

Reporting a vulnerability

See /.well-known/security.txt. Please report issues privately.