Zero-Knowledge by Default: How ShareZT Protects Your Secrets
An updated look at the security model behind the gate.
ShareZT exists to put a real checkpoint in front of a link. Anyone can paste a URL into a shortener; the harder problem is making sure that only the right person, in the right place, at the right time, ever reaches what's on the other side — that abusive traffic can't wear the gate down, and that when access should end, it actually ends.
For secrets, we've now taken that a step further. ShareZT can hold a secret in a way where we ourselves cannot read it — not an engineer, not our database, not our servers if they were fully compromised. This post walks through how that works, alongside the server-side gate it sits behind, and is honest about exactly where the trust boundaries fall.
Two independent locks
The clearest way to understand the model is that a protected secret is behind two separate locks, and we only ever hold one of them.
The first lock is the gate: the access decision that runs on our servers and determines who is even allowed to receive the protected content. The second lock is the key: the cryptographic key that turns the received content back into readable plaintext. The gate controls delivery; the key controls readability. They are deliberately independent — and for a zero-knowledge secret, the key is one we never possess.
That separation is the whole design. Clearing the gate gets you an encrypted blob and nothing more. Holding the key, without clearing the gate, gets you nothing to decrypt. Both have to line up, and the most sensitive of the two — the key — never touches our infrastructure.
Zero-knowledge encryption, by default
When you create a text secret, the encryption happens in your browser, before anything is sent to us. ShareZT generates a fresh 256-bit key locally, using your browser's built-in Web Crypto — vetted platform cryptography, not anything we rolled ourselves — and encrypts your secret with AES-256-GCM. Only the resulting ciphertext is transmitted to ShareZT. The key stays on your machine.
The key then travels in one specific place: the fragment of the share link — the portion after the #. This is the quiet but crucial detail. Browsers, by long-standing design, never send the fragment of a URL to the server. So when someone opens your link, the token that identifies the ciphertext reaches us, but the key in the fragment never does. The recipient's browser reads the key locally and decrypts there.
What this buys you is concrete: ShareZT stores only ciphertext and never sees the key. We cannot read your secret to satisfy our own curiosity, to answer a support request, to comply with a demand for our stored data, or after a breach of our systems. There is nothing on our side to decrypt with. That is what "zero-knowledge" actually means, and we only use the term because it's literally true here.
AES-256-GCM also makes the secret tamper-evident. GCM attaches an authentication tag, so altering the ciphertext by even a single byte causes decryption to fail outright rather than return corrupted or attacker-shaped data. The secret you encrypted is the secret that gets read, or no secret at all.
Where the trust boundary sits, stated plainly: because the key lives in the link, the complete link is the secret. Anyone who has the full URL — fragment included — and who clears the gate can read the contents, so share it over a channel you trust, and lean on the gate (expiry, a passphrase, IP or geo limits) for the second lock. And because we never hold the key, we cannot recover a secret if the link is lost. That is not a gap; it is the direct cost of the guarantee, and we think it's the right trade for a tool whose job is to keep secrets.
When you'd rather we hold the key
Zero-knowledge is the default, but it isn't always what you want. If you need to read a secret back from your own dashboard, or hand it to a recipient who can't run encryption in their browser, you can choose server-side encryption instead. In that mode the secret is still encrypted with AES-256-GCM at rest, under a key ShareZT manages — strong protection against a stolen disk or database, but with the honest caveat that we can decrypt it in order to serve it. You pick the mode per secret. We default you to the stronger guarantee and let you opt down deliberately, rather than the other way around.
The gate: decide on the server, fail closed
The second pillar is the gate, and its governing principle is simple to state: every access decision is made on our servers, and the default is to deny.
A lot of "protected link" tooling runs its checks in the visitor's browser — a script decides whether to reveal something, and if the script is bypassed, the content leaks. That's fail-open: when something goes wrong, the gate swings the wrong way. ShareZT inverts that. The payload is held server-side and is never handed to a visitor until the request has passed every check, and if a check can't be completed — say a lookup is unavailable — the request is denied rather than waved through. A gate that can't verify you doesn't guess in your favor.
Each request runs through an ordered pipeline, and a failure at any stage stops it there:
- Rate / flood control — abusive request volumes are throttled before any real work happens.
- Lifecycle — is the link revoked, expired, or past its view limit? Spent links never reach the later stages.
- IP access rules — allow-lists and block-lists, evaluated against the true visitor address.
- Geo-fence — country-level allow or block rules.
- Password — a per-link passphrase, when one is set.
The cheapest, most definitive checks run first; the costlier ones only run for requests that have already earned them. For a zero-knowledge secret, this gate guards the ciphertext while the fragment key guards the content — so even a visitor who somehow slipped past the gate would come away holding only an unreadable blob.
Getting the visitor's real identity right
Network rules are only as trustworthy as the address they evaluate. A common, quiet failure in layered infrastructure is that by the time a request reaches the application, the "client IP" has been rewritten to some intermediate hop — so an IP, geo, or rate-limit rule ends up judging your own infrastructure instead of the visitor.
ShareZT carries the genuine client address end-to-end so that every per-visitor decision evaluates the actual visitor. Just as importantly, the application only accepts that forwarded identity from its own trusted edge; a request that tries to assert its own address from elsewhere doesn't get to. IP rules support individual IPv4 and IPv6 addresses and CIDR ranges, matched precisely rather than by string prefix, and geo-fencing — true to the fail-closed principle — denies access when a location simply can't be established.
Burn-after-read that actually burns
"Burn after read" is only meaningful if reading really destroys the thing. When a burn link is opened and clears the gate, the stored ciphertext is deleted from storage, not merely flagged as used. After that read there is nothing left to recover — not through the link, not through the API, not in the database. The same destruction applies when a secret reaches the end of its life another way: once it has expired or hit its view limit, its ciphertext is removed, and a background process ensures nothing lingers even if the link is never reopened. Manual revocation is treated differently on purpose — because revoke is meant to be reversible, it disables a link without destroying its contents, so an accidental revoke can be undone.
One honest detail specific to zero-knowledge: because the key never reaches us, we can't confirm a visitor actually holds the right key before serving. So opening a zero-knowledge burn link consumes it on access, even if the fragment is wrong or truncated — the same behavior as classic one-time-secret tools, and the reason the interface tells you to share the whole link. For server-side secrets, where we can see the result, the secret is decrypted before the read is counted, so a single entitled view is never silently spent on a damaged secret.
Staying available under abuse
A gate that can be exhausted isn't much of a gate. ShareZT bounds the work any single source can demand: sign-in attempts, account creation, link creation, and traffic to a protected link each carry their own ceiling, after which further requests are turned away with a clear retry signal. Repeated wrong passwords on a protected link trigger a temporary lockout, so a passphrase can't be ground down by guessing. And because verifying a password is intentionally slow work — that slowness is what resists guessing — it's handled so that a burst of attempts from one source can't stall service for everyone else. An abusive client mostly succeeds in rate-limiting itself.
Accounts, credentials, and keys
The front door gets the same care as the gate. Account passwords are stored only as salted bcrypt hashes, never in plaintext, and compared in constant time. API keys are shown once, at creation, and stored only as hashes — ShareZT can verify a key but cannot reproduce one, so a database compromise doesn't hand over a set of working keys. Session cookies are HTTP-only, same-site, and secure in production, keeping them out of reach of page scripts and curbing cross-site request forgery. And authentication failures return the same generic response whether or not an account exists, so the sign-in form can't be used to discover which emails are registered.
You also get visibility into all of this: access decisions and sign-in events are logged, and an in-product security view surfaces blocked attempts, failed sign-ins, and the addresses behind repeated denials — so you can watch the gate doing its job rather than take our word for it.
The quiet fundamentals
Underneath everything are a few baseline practices that don't make headlines but do most of the day-to-day work: parameterized database access throughout, so input is always treated as data and never as executable query; strict per-account isolation, so one account cannot reach another's links, rules, or analytics; and escaped output on every page we render — including secret-reveal pages, served with caching disabled so nothing is left behind in a browser or proxy cache.
What we can and can't promise
We'd rather be precise than impressive. Once a recipient decrypts a secret on their own device, it lives on that device, and what happens next is outside our boundary — zero-knowledge protects the secret in transit and at rest with us, not against a compromised endpoint. IP and geo signals are best-effort by nature; VPNs, proxies, and the limits of geolocation mean they raise the bar rather than form an impervious wall, which is exactly why a geo-restricted link fails closed when it can't be sure. And zero-knowledge cuts both ways: the same property that stops us from reading your secret stops us from rescuing one whose link is gone.
None of this is a claim of perfection. Good security is layered, and it's continuous — we keep tightening the parts you can see and the parts you can't. What we can say is that the model rests on principles we don't compromise on: the most sensitive key never reaches us, decisions happen on the server, the default is to deny, abuse is bounded, and access that should be over is actually over.
Have a question about how ShareZT handles a specific scenario? We're happy to get into the details.