Threat Model
weekkii stores your task content as opaque ciphertext, along with the metadata around it (day, ordering, completion and archive times, recurrence links, timestamps) for every new or edited task. Tasks you created before this rollout and have not edited since keep their metadata in plaintext until you next edit them (see section 3). This page states precisely what we can and cannot see, what we defend against, and the limits we do not claim.
1. Trust model
We assume an honest-but-curious server: our infrastructure runs the code we deploy and does not actively attack you, but could be compelled, breached, or observed. Our goal is that a party with full read access to the database learns as little as possible about your tasks. We also defend against a passive disk/forensic adversary on your own device and against other users or unauthenticated callers. We do not claim protection against an actively malicious server that serves you tampered data, nor against an attacker who already runs code in your browser or has your unlocked device.
2. What we cannot see
Task titles, notes, tags, and recurrence rules are encrypted on your device before upload. So is the per-task metadata — which day a task is on, its order, completion and archive times, recurrence links, timestamps — for every new or edited task; it now lives inside the encrypted blob and the plaintext columns are blank. Your settings, list names, and tag metadata are encrypted too. Your master passphrase and the key derived from it never leave your device; there is no escrow and no reset. The one residual is tasks created before this rollout that you have not edited since — those keep their plaintext metadata until you next edit them (we deliberately did not force-rewrite or delete your old rows).
3. What we necessarily see
Your account email (to send the sign-in code); that a row exists, a random row id, your user id (to enforce per-user access), and an opaque counter we assign on each write — it reveals the order and count of your edits, never when they happened or what changed. For legacy tasks not edited since the rollout, we still see their day, ordering position, completion and archive timestamps, and recurrence links until you next edit them. Ciphertext is padded to fixed size buckets so content length is not directly inferable. Plus billing facts (below) and standard infra logs (IP, timestamp, user-agent, kept ≤30 days).
4. Data at rest on your device
Task content is stored locally only as ciphertext. The master key is held in memory while unlocked and, between sessions, wrapped under a non-extractable device key (IndexedDB on web; Keychain/Keystore on native). Your session token is not kept in plaintext browser storage — it is encrypted under the same device key wrapper. We refuse to operate on a browser without IndexedDB + Web Crypto in a secure context rather than store anything in the clear.
5. Out of scope (necessarily server-known)
Account existence + email (sign-in codes need it); billing facts — plan, status, trial dates, Dodo customer id — since Dodo Payments is the Merchant of Record and these are not task content; and infrastructure logs. The stored payment-webhook record is redacted to identifiers only.
6. Residual risks we are explicit about
- In-origin code execution (XSS, hostile extension, compromised dependency) could read your session token and act as you at the API, but still cannot read your plaintext. Our strict Content-Security-Policy and no-third-party-JavaScript rule are the primary controls.
- An actively malicious server cannot read or forge your content, but could withhold or roll a single row back to an earlier encrypted state — an integrity/availability limit, never a confidentiality one.
- An unlocked or forensically-accessible device within the re-validation window exposes your data — the standard trusted-device assumption.
- No recovery. Lose your passphrase and your content is gone. There is no backdoor, by design.
7. Cryptography
Content: XSalsa20-Poly1305 (NaCl secretbox), random 24-byte nonce per encryption, bucket-padded plaintext, row-id/user-id context binding. Key derivation: Argon2id (OWASP-2024 interactive: m=19,456 KiB, t=2, p=1) with a 16-byte CSPRNG salt; the client enforces both a floor and a ceiling on key-derivation parameters. Transport: TLS 1.3 with HSTS preload.
8. Contact
Security questions or disclosures: weekkii@festivlabs.com.