Skip to main content

Security

Threat Model

A security tool is only meaningful relative to a specific adversary. This page lists the attackers we designed against, states honestly where the design stops working, and tells you when you should be using something else.

Last reviewed Reviewed by Inkrypt Security Team

Why an explicit threat model matters

"Is this secure?" is not an answerable question. "Secure against whom, doing what?" is. A tool that comprehensively defeats a database breach may be useless against malware on your laptop, and saying so is the difference between a security product and a security-flavoured one.

The cost of vagueness is real. Someone who believes a tool protects them against an adversary it does not defend against will take a risk they would otherwise have avoided. That is a worse outcome than using nothing.

Adversaries Inkrypt defends against

An attacker who breaches our database

Strongly defended. An attacker who exfiltrates every row obtains AES-256-GCM ciphertext, per-note random salts and IVs. There is no master key to steal, because none exists. Each note must be attacked independently, offline, against whatever password protects it — and per-note salting means cracking one gives no advantage on the next.

A network attacker

Strongly defended. All traffic is TLS, but more importantly the plaintext never enters the network at all. Even a complete break of TLS on a given connection would reveal only ciphertext, a salt and an IV.

Us — the service operator

Strongly defended, structurally. There is no code path in which our servers hold a decryption key. This is not a promise not to look; it is the absence of the capability to look. It follows that a legal demand can only produce ciphertext.

Defended, provided you split the channels. A share token retrieves ciphertext; the password decrypts it. Someone with just the link holds unreadable data. This protection evaporates entirely if you send both in the same message — see secure link sharing.

Long-term accumulation of secrets

Defended by expiry. The specific risk that a credential shared in 2023 is still readable in a chat archive today is addressed directly: expiry and view limits mean a stale link stops working by default, rather than staying live because nobody remembered to revoke it.

Adversaries only partially mitigated

An offline password-guessing attack

Partially mitigated. PBKDF2 at 310,000 iterations multiplies the cost of every guess, and per-note salts prevent precomputation and amortisation. But an attacker holding your ciphertext can grind at their own pace with no rate limit we can impose. Against a weak password, key stretching buys time and nothing more.

Your password is the binding constraint on this entire system. Four or more random words moves it from "hours" to "not worth attempting".

Partially mitigated. Corporate mail filters and chat link-preview bots fetch URLs automatically, which can consume a view-limited link before the human clicks. They obtain only ciphertext, so this is an availability problem rather than a confidentiality one — but it is a real and common annoyance. Allow two or three views when sending into a filtered environment.

Traffic and metadata analysis

Partially mitigated. We cannot read notes, but we necessarily observe that a request occurred, when, and against which slug. Slugs are not encrypted. An observer with access to our logs learns nothing about content but does learn that a note by a given name existed and was fetched.

Adversaries Inkrypt does not defend against

Malware on your device

Not defended. A keylogger or infostealer on your machine sees plaintext as you type it and captures the password as you enter it. Encryption happens after that point. No browser-based tool can defend below its own layer — if your endpoint is compromised, nothing running on it can be trusted.

The recipient

Not defended, and not defensible. Once someone can read a note they can screenshot it, copy it, photograph the screen or simply remember it. Expiry controls availability from our servers; it has no reach into anyone's memory or clipboard. Any product implying otherwise is misleading you.

A compromised or malicious code-delivery layer

Not defended. We serve the JavaScript that performs the encryption. A compromised operator — or an attacker with control of our delivery pipeline — could serve modified code that exfiltrates passwords. This is the fundamental limitation of all browser-delivered cryptography, and it applies to every web-based encryption tool without exception.

If this is your adversary, use something else

Against an attacker capable of compelling or compromising a service provider at the code-delivery layer, use an installed application with a signed, independently verifiable build — ideally one that has been externally audited. We would rather send you elsewhere than have you rely on the wrong tool.

A forgotten password

Not defended, by design. There is no recovery. If we could restore access, we could read your notes — the two capabilities are identical. Availability is deliberately traded away for confidentiality.

Not defended. Nothing here helps if someone can compel *you* to reveal the password. There is no duress mode and no plausible-deniability construction.

Known limitations we accept

The sections above describe adversaries. This one describes decisions — places where the current implementation is weaker than a reader might reasonably assume from the headline parameters. We publish them because a threat model that omits its own awkward parts is not a threat model, and because each one changes how you should use the product.

Share passwords are stored as an unsalted SHA-256 hash

What it is. When you protect a share link with a password, the server keeps a single-round, unsalted SHA-256 of it to check against what a recipient types. Hashes of that kind are fast to compute, which is exactly what you do not want: they are open to precomputed lookup tables and to very high-rate guessing, unlike the 310,000-iteration derivation protecting the content.

What it does not mean. That hash is not the decryption key and the ciphertext is not protected by it. The snapshot remains AES-256-GCM under a PBKDF2-derived key with a fresh random salt, exactly as described on the security architecture page. A database breach does not hand anyone your share contents.

What it does mean. For a password-protected share, the password you type *is* the key the content is derived from. So if an attacker holds both the stored hash and the ciphertext, recovering a weak password from the fast hash also recovers the content — and the expensive key derivation buys you nothing, because it is no longer the slow step.

What to do about it. If you set a share password, make it long and random rather than memorable — a generated passphrase, not a word you will recognise. If you do not specifically need the recipient to type something, use a passwordless share instead: the key is then a random value your browser generates and places in the link fragment, which is never transmitted to us and never stored in any form.

Expiry times and view limits are properties of a share link, not of the note behind it. A note itself has no expiry mechanism: once created, its encrypted record persists until you overwrite it. When a share link expires, the share snapshot stops being retrievable — the note is untouched and still opens with its own password.

This surprises people who read "self-destructing" as applying to everything. It does not. If you need a note to stop existing, you must overwrite its contents yourself; there is no scheduled deletion to rely on.

Note names are stored in the clear

A note's name is its URL, and it is stored unencrypted. We can see that a note exists at a given name, when it was created and when it was last written — we simply cannot read what is inside it. Names also travel further than content does: into browser history, bookmarks, and anywhere the link is pasted. Treat the name as public, and keep the meaning inside the note.

The code-delivery problem is not solved, only disclosed

We describe this above as an adversary we do not defend against, and it belongs here too, because it is a limitation we have accepted rather than one we have mitigated. Every visit fetches our JavaScript and runs it, so the integrity of the encryption depends on the integrity of what we serve. What we can offer is that the claims on this site are checkable in your own browser — the method is set out in what zero-knowledge encryption actually means — and that we would rather document the gap than let it be inferred.

Summary

Inkrypt's posture against each adversary class. Read the rows marked 'No' before deciding.
AdversaryDefendedBasis
Database breachYesServer holds only ciphertext; no master key exists
Network interceptionYesPlaintext never transmitted
The service operatorYesNo key ever present on our infrastructure
Legal demand for contentYesOnly ciphertext can be produced
Leaked share link aloneYesLink retrieves ciphertext; password is separate
Offline password guessingPartial310,000-iteration KDF; bounded by password strength
Metadata observationPartialSlugs and request timing are visible to us
Malware on your deviceNoPlaintext exists before encryption runs
The recipient copying itNoOutside any technical boundary
Compromised code deliveryNoInherent to browser-delivered cryptography
Forgotten passwordNoDeliberate — recovery would mean we hold a key
Coercion of the password holderNoNo duress or deniability mechanism
Inkrypt's posture against each adversary class. Read the rows marked 'No' before deciding.

If your situation falls in the bottom half of that table, the honest answer is that Inkrypt is not the right tool, and we would rather tell you that here than have you find out later.

The primitives referenced above are specified in NIST FIPS 197 for AES, NIST SP 800-38D for GCM and its authentication tag, and RFC 8018 for PBKDF2. The limits of key stretching against weak passwords are discussed in the OWASP Password Storage Cheat Sheet, and the browser-delivery problem is a property of the Web Cryptography API execution model rather than of any particular implementation.

Frequently asked questions

Is Inkrypt safe for highly sensitive information?

It depends entirely on your adversary. Against database breaches, network attackers and legal demands for content, the design is strong. Against a compromised endpoint or an adversary who can compel a provider to serve modified code, it is not — use an audited, installed application instead.

What is the single biggest weakness?

Two, closely related. First, password strength — key derivation slows guessing but cannot fix a weak password. Second, the fact that we serve the code that performs the encryption, which is inherent to all browser-based cryptography.

Could Inkrypt be forced to serve me modified code?

In principle, yes — that is true of every web application, and we would be misleading you to claim otherwise. It is why the threat model above places a compromised code-delivery layer firmly in the 'not defended' column.

Does encryption protect me from the person I share with?

No, and nothing can. Once someone can read a note, the content is in their control. Expiry limits how long they can retrieve it from us — it does not limit what they do with what they already read.

How often is this threat model reviewed?

Whenever the architecture changes, and at least annually. The review date is shown at the top of this page, and material changes are recorded on the changelog.

Think we have the model wrong?

We would rather be corrected than be confidently mistaken. Our responsible disclosure policy explains how to reach the people who maintain this page.

Open the notepad