Cinderburn after reading

// how it works

One link, one PIN, one message at a time.

If a privacy tool will not explain itself, do not trust it. Here is exactly what happens to your PIN, your link and your messages, and where the protection stops.

The lifecycle

  1. 1 · The PIN becomes the key, locally

    Your browser runs 600,000 PBKDF2-HMAC-SHA256 rounds over the 4-digit PIN and a random 16-byte salt, producing a 256-bit AES-GCM key. The PIN itself is never transmitted, logged or stored anywhere.

  2. 2 · The server gets a check blob, not a password

    So the other side can tell a right PIN from a wrong one without the server learning it, the room stores an encrypted marker. Each browser decrypts it locally: success means the PIN was correct. The server only counts failed attempts.

  3. 3 · One message exists, and only until it is read

    A room holds exactly one row. Sending replaces it, so a new message from either side destroys the previous one. The instant a message decrypts on the other device, the row is deleted with secure_delete on, which zeroes the freed pages.

  4. 4 · Idle rooms expire

    Any activity pushes expiry out by 24 hours, capped at 7 days from creation. When a room expires, its message and metadata are deleted, not archived.

What the database stores

id
Random 18-character room identifier: the only thing in the link path.
salt + check blob
A 16-byte salt plus an encrypted “ok” marker. The server can confirm nothing about your PIN from these.
message ciphertext
The single message in flight, sealed with AES-256-GCM.
iv
The 12-byte nonce used for that one encryption.
timestamps
Created, last activity (rooms expire after 24 idle hours) and when a message was read.
attempts
How many wrong PINs have been tried, so the fifth can end the room.

What is never stored

  • Your 4-digit PIN, in any form: it never leaves the browser
  • The room key (derived from the PIN with 600,000 PBKDF2 rounds)
  • Message plaintext: not in the database, not in logs, not in memory on the server
  • Your IP address, user agent, device fingerprint or an account of any kind
  • Message history: only one message ever exists at a time, and it is deleted on read

Crypto parameters

Message cipher
AES-256-GCM, 96-bit IV, per-room key
Key derivation
PBKDF2-HMAC-SHA256 · 600,000 iterations · 16-byte salt
PIN verification
Encrypted check blob decrypted in the browser, never checked server-side
Attempt limit
5 wrong PINs destroys the room
Transport
HTTPS only, responses marked no-store, referrer suppressed
Storage
SQLite with secure_delete + auto_vacuum
Room lifetime
24 hours idle, 7 days maximum
Message lifetime
deleted the moment it is read, replaced when a new one is sent

Threat model, honestly

  • Someone reads the database

    They get one sealed message, a salt and a check blob. Without the PIN there is nothing readable.

  • The link leaks

    The link alone opens nothing; the PIN is the key. This is why the link is useless in a group chat.

  • Someone guesses the PIN

    Five tries, then the room is destroyed for everyone. Guessing burns the target instead of opening it.

  • A stolen phone with the chat open

    The plaintext lives in that tab's memory only. Close it and it is gone. Nothing is cached or written to storage.

  • The recipient screenshots it

    Nothing can prevent that. One-message-at-a-time limits the window, it does not control the reader.

  • The server operator

    We can delete rooms and see counts, but we cannot decrypt a message: the key is derived from the PIN inside your browser.

The honest caveat: a 4-digit PIN is only 10,000 combinations. The attempt limit and 24-hour lifetime are what make it workable, but for anything that must survive a determined attacker, use a long passphrase or a dedicated password manager instead of a PIN you invented in five seconds.

Convinced? Create a link and hand the PIN over separately.

Create a link

Cinder · one message at a time · no accounts, no history