engineering / security

The strongest security control here is architecture: there is nothing to breach.

No backend means no server holding your audio, your transcripts or your key. What remains to secure is the page itself — and that work is done in public, including the parts still open.

The threat model

What we hold, what we never see

Your audio & transcripts

Processed in your browser and sent by your browser directly to the model provider via OpenRouter, under your key. Nothing is uploaded to us — there is no "us" to upload to. In routed mode we honestly cannot promise WHICH provider processes a recording; the landing page says so rather than hiding it.

Your OpenRouter key

Bring-your-own-key: pasted by you, stored only in your browser's localStorage, sent only to OpenRouter. The page's job is to make sure no other code can ever run where that key lives — see the hardening below.

What we collect

Nothing. No analytics, no accounts, no cookies, no server logs of your content. The footer's claim — "nothing tracked, nothing stored server-side" — is an architectural fact, not a policy promise.

Hardening, in public

The app page's own defences

A public review (v0.1.20, 6 Aug 2026) graded the app's security findings S1–S5. The state below is kept honest — shipped means shipped, open means open.

FindingDefenceState
S1 — a crafted ?origin= link could load attacker code into the page that holds the key The parameter was removed entirely — the engine origin is a hardcoded constant, and a test asserts the config never reads the query string (two teams allow-listed it independently the same day; deleting the feature beat both) SHIPPED
S2 — no Content-Security-Policy Meta CSP pinning script and connection sources to exactly the origins the app uses SHIPPED
S3 — the chat model can persist prompt overrides across sessions Human confirmation (or de-scoping) of the prompt-writing chat tools OPEN
S4 — model-generated SVG enters the DOM Verify upstream sanitisation or strip event handlers locally; hostile-content render tests OPEN
S5 — key-name hygiene, key validation on save, one unescaped interpolation Rename + migrate the localStorage key; validate via key status; escape OPEN

The full findings, with file-and-line citations, are published in the repo — publishing your own security review is unusual; for a no-backend product, openness genuinely shrinks the attack surface rather than growing it.

The line

The ciphertext rule: what may be public, what must never be

This repo is public and always will be. The line between publishable and secret is written down and enforced as a rule, not left to judgement per commit:

MAY live in this public repoMUST NEVER be committed
An encrypted vault (ciphertext)The vault key
Key-management logic and provisioning workflow codeAny plaintext secret
Configuration and schemasThe OpenRouter management API key
The security review itselfAnything that decrypts what is committed

Automated enforcement (a secrets scanner in CI and a pre-commit hook) is tracked as issue 013 OPEN — the rule currently lives in the rulebook and in review.

Receipts
  • Issue 037 — the hardening queue, with what shipped when
  • The AppSec model-allowlist review — the five models the app may call, verified in code
  • A full privacy notice is being written (tracked with the DPO role) — until it ships, this page and the open repo are the record