We can't read your private pastes — and you can check.
When you toggle private, pste encrypts the paste in your browser before it is uploaded. The server stores ciphertext it cannot decrypt. This page explains exactly how that works, what we can still see, and how to verify the claim instead of trusting it.
How end-to-end encryption works
A 256-bit AES-GCM key is created in your browser with the Web Crypto API. It never leaves your machine in a form the server can use.
Your content is encrypted locally. Only the ciphertext — a random 12-byte IV followed by the AES-GCM output — is sent to the server.
The share link ends with #k=…. Everything after the # is the
fragment — by the design of the web, browsers never send it to the server. The key
reaches readers, never us.
Opening the link, the reader's browser pulls the ciphertext, reads the key from the fragment, and decrypts locally. The server is never in possession of both halves.
What the server can and can't see
- The ciphertext bytes of an E2E paste — random-looking, useless without the key
- Metadata: byte size, creation time, expiry, and whether the paste is E2E or burn-after-read
- Your IP address, briefly — used for rate limiting and abuse handling, not stored long-term
- For non-E2E pastes only: the plaintext content (that is the trade-off of not toggling private)
- The plaintext of an E2E paste — it is encrypted in your browser before the upload leaves
- The decryption key — it is generated in your browser and lives in the URL fragment (#k=…), which browsers never send to servers
- Your passphrase, if you password-protect a paste — only a key derived from it ever exists, and only in your browser
How to verify it yourself
Don't take our word for it — the claim is checkable:
- The code is public. pste is source-available on GitHub.
The entire encryption implementation is one short file —
src/lib/e2e.ts, about 100 lines — and the same module runs in the editor, the viewer, and the test suite. - The bundle is content-addressed. The JavaScript pste serves has a hash in its filename. It changes only when the code changes, so you can pin and diff what your browser actually ran against the public source.
- You can watch the network tab. Create a private paste with dev tools
open: the request body is ciphertext, and the
#k=…fragment never appears in any request.
The honest limit: like every in-browser encryption tool — Proton, Bitwarden's web vault, anything that decrypts in a tab — you are ultimately trusting the server to ship honest JavaScript each visit. End-to-end encryption removes us from your data; it does not remove us from your browser. Our answer to that is the same as theirs: keep the code small, keep it public, and make the served bundle diffable against it. We'd rather state this plainly than let the lock icon imply more than it delivers.
What E2E does not protect against
- Anyone with the full link. The key is in the URL. Sharing the link shares the ability to decrypt — treat private paste URLs like passwords.
- Metadata. We still see that a paste exists, its size, and when it was made. E2E protects content, not the fact of it.
- Anonymity. E2E is confidentiality, not anonymity. Your IP is visible to us at upload time for rate limiting, the same as any website.
- Your own devices. If someone has your screen, your clipboard, or your browser history, encryption at rest on our side doesn't help.
Reporting a vulnerability
Found a security issue? Email security@pste.dev. We'll acknowledge it, keep you
posted, and credit you if you'd like. Please don't open a public issue for anything
exploitable until it's fixed.