bongsmoke.cloud
Threat model

What this protects.
And what it does not.

A security page that only lists strengths is marketing. The second half of this one is everything this service cannot do for you, including the parts that are inconvenient to admit.

What the service can and cannot see

Your message is encrypted in your browser with AES-256-GCM. The ciphertext travels in the URL fragment — the part after # — which browsers do not transmit. It is not in the request line, not in the Referer header, and not in any server log, ours or anyone else’s along the way.

So the server never receives the plaintext. It also never receives the ciphertext. There is no endpoint that accepts one and no column that could hold one. This is not a policy we are promising to keep; it is a shape the system does not have.

What the server does hold is one of the two halves of the key.

The split

HalfWhere it livesWho has it
Client share256 random bits, inside the link fragmentWhoever holds the link
Server shareHMAC-SHA256(secret, noteId)Recomputed on demand; released once

HKDF-SHA256 over their concatenation produces the AES-256-GCM key, salted with the note identifier. An optional passphrase contributes a third share via PBKDF2-SHA256 at 600,000 iterations over a random 128-bit salt carried in the fragment.

The note identifier is bound in as GCM additional authenticated data. A ciphertext lifted out of one link and pasted under a different identifier will not decrypt — it fails the authentication tag rather than producing garbage.

Why the expiry can sit in the identifier in the clear

A note identifier is 128 random bits plus its expiry. The expiry is readable by anyone. It is also an input to the HMAC, which means editing it produces a different identifier, therefore a different server share, therefore a key that decrypts nothing. Tampering is self-defeating. The server independently refuses any identifier whose expiry is in the past or further out than the longest lifetime it offers.

One-time release

Reveal performs a single atomic SET <hash> 1 NX EX <ttl>. The first caller creates the marker and receives the share; every subsequent caller, including ones arriving in the same millisecond in different regions, is told the note is gone. There is no read-then-write window.

If storage is unreachable, reveal returns a 503 and no share. A note that cannot be marked burned is not opened. The failure mode is “temporarily unavailable”, never “quietly readable twice”.

What is stored

Burn markers
One byte of value under a key derived from a keyed hash of the note identifier — not the identifier itself. Expires when the note would have expired anyway.
Rate-limit counters
An integer per endpoint per ten-minute window, keyed by a hash of the caller’s IP address rather than the address itself. Also expires on its own.
Nothing else
No user table, no message table, no ciphertext, no key share, and no log of what was created. Creating a note writes nothing at all.

What this does not protect you from

Anyone who sees the link can read the note

The link is the credential. There is no second factor unless you add a passphrase. If the link passes through a channel someone else can read — a shared inbox, a logged corporate proxy performing TLS interception, a group chat, a screen behind you — that person can open the note. Your recipient will then find it already burned, which is the only signal you get that it happened.

Corollary: a burned note that the recipient never opened is evidence of interception. It is worth treating as such.

The link persists in places you do not control

The fragment is part of a URL, and URLs are sticky:

We clear the fragment from the address bar once a note is decrypted, but that only touches the current tab. It cannot reach into the sender’s history or the messaging app that carried the link.

A reader can keep the note

Burning destroys the key, not the reader’s memory, their screenshot, their clipboard, or the text file they pasted it into. “Self-destructing” describes the service, not the recipient. If you would not want it written down, a note that deletes itself does not change that.

Whoever controls this site could serve different code

All the cryptography runs in JavaScript this site serves. Anyone able to modify what is served — a compromised deployment, a stolen hosting credential, a malicious commit — could serve a version that exfiltrates the fragment before decrypting it. This is the fundamental limitation of browser-delivered cryptography and no amount of client-side design fixes it.

What is done about it: no third-party scripts, no analytics, no fonts or assets from other origins, and a Content-Security-Policy with connect-src 'self' that leaves an injected script nowhere to send anything. What is not: there is no code-signing or reproducible-build story, and you are trusting the deployment.

Metadata is not hidden

We do not log request bodies or note identifiers, but the hosting platform records HTTP requests as every host does. The existence and timing of a note being opened is observable to someone with access to those logs, along with the address that opened it and the identifier in the request path.

That is a privacy leak, not a confidentiality one: the identifier alone cannot decrypt anything, because the client share never appears in any request. But someone with log access could open a note before its recipient, which would burn it. The threshold for that is “already has access to our infrastructure logs”.

Ciphertext is padded to size buckets, so the length of a link reveals only which bucket a message fell into, not its size.

The passphrase is PBKDF2, not Argon2id

Argon2id is the better choice against GPU-accelerated cracking, and we are not using it. The honest reason is dependency and policy cost: the audited implementations are WebAssembly, which would require 'wasm-unsafe-eval' in the script policy and add a binary to the trusted bundle of an app whose entire pitch is that it is small.

PBKDF2-SHA256 at 600,000 iterations is OWASP’s current floor. It is also not the only thing standing between an attacker and the plaintext — they would need the link’s client share and the one-time server share as well. Choose a passphrase accordingly: it is a third factor, not a password protecting a database dump.

Not covered at all

Reporting something

If you find a flaw in any of this, the service itself is a reasonable way to tell us about it: write it up, and send the link to the address on the domain’s WHOIS contact. If you believe it is a working exploit, please describe the class of problem rather than publishing a recipe.

Write a note