Skip to content

Security and Encryption

Michael Dohmen edited this page Aug 13, 2026 · 3 revisions

Security and Encryption

What encryption protects — and what it doesn't

Encryption protects the data, not access to the application. This is worth internalising before relying on it: roles, views, or any notion of "some people can see this, others can't" implemented inside a file that runs entirely locally would be surface-level only. Whoever holds the file holds the code that reads it — there's no server-side boundary to enforce anything. What encryption does give you: without the passphrase, the data is an opaque blob. Lose the file to the wrong person without the passphrase, and they get nothing.

The mechanism

  • AES-256-GCM for the actual encryption — authenticated encryption, so tampering with the ciphertext is detected, not just confidentiality.
  • PBKDF2 with 310,000 rounds (SHA-256) to derive the encryption key from your passphrase — a deliberately expensive key derivation to make brute-force guessing costly, per current OWASP-adjacent guidance for this construction.
  • A fresh random salt and IV on every encryption. Encrypting the same data twice with the same passphrase produces different ciphertext each time.
  • No back door. There is no recovery mechanism, no master key, nothing. Losing the passphrase means losing the data — the settings page says this plainly before you set one.

Everything here is the browser's native Web Crypto API (crypto.subtle) — no crypto library is bundled, which keeps the file small and means the primitives are whatever your browser's own, audited implementation provides.

What sits outside the encrypted envelope, and why

Settings (theme, title, colours, language, branding) are stored unencrypted, deliberately, even in an otherwise-sealed file. The alternative — encrypting everything — would mean the lock screen itself couldn't show the right title, logo, or colour scheme before you've entered the passphrase, which is a worse experience for no real security gain: none of that is sensitive.

The one exception that is sensitive and handled explicitly: if the AI integration's API key is stored with the file at all (opt-in, off by default — see AI Assistant), it only ever goes into the encrypted envelope if the file is sealed. Storing a key in an unsealed file is still possible if you explicitly ask for it (a "store the key" toggle), but the settings page says outright that the key would then sit in plain text in a file that gets passed around.

Passphrase strength: a hint, not a gate

Settings shows a live strength rating (weak/usable/solid) as you type a passphrase, based on length and character variety. It never blocks you from proceeding with a short one. The reasoning: there are legitimate cases where a file only needs protection against casual, accidental reading — e.g. it already lives on a managed, access-controlled corporate drive — and forcing a long passphrase in that case is friction without benefit. The hint tells you the trade-off; you decide.

Weak points worth knowing, honestly

  • Whoever holds the file holds the code. This is a client-only app; there's no way to hide business logic or "premium feature" gating from someone who has the HTML file, since that HTML file is the entire application.
  • The unencrypted settings block is readable by anyone, including product name and branding — by design, and not sensitive.
  • Browser Web Crypto availability: if a browser context doesn't expose crypto.subtle (rare, but possible in some restricted embedding contexts), the encrypt dialog says so plainly rather than failing silently — "open the file in a current Chrome or Edge" instead of a broken dialog.
  • No multi-user access control, ever. See Limits and Troubleshooting for what "one machine, one file" actually means in practice.

If you're auditing this for a regulated environment

The properties worth pointing a security reviewer at:

  • No network access at all unless the AI integration is explicitly turned on (verifiable: open dev tools, watch the network tab, there's nothing there with AI off).
  • No telemetry, no analytics, no external asset loading of any kind — the built file is fully self-contained; npm run build's CI check fails the build if it finds an external <script src= or <link href="http.
  • Source is readable end-to-end — nothing obfuscated or minified beyond standard build minification, and the source repository is the same code that produces the shipped file.
  • The AI integration, when turned on, sends data to exactly one endpoint: whatever's configured in Settings. There's no hidden secondary destination.

Clone this wiki locally