Security and privacy
How we protect your data.
The short version: every sensitive field is encrypted on your device with a key made from your password. Our servers hold the encrypted blob and have no way to read it. The longer version is below, in plain language. Last reviewed 2026-05-10.
The promise
Your questionnaire answers, your Living Household Plan, your roster, your medications, your inventory, your drills, your resilience check-ins, none of it is readable by the RainWillCome team.
One honest limit, named plainly because that is part of doing this right: the vault we store, we cannot read. Your key is made on your device and never sent to us, so what sits on our servers is ciphertext with nothing to open it, that is the design, not a matter of our goodwill. Like every encrypted service where the provider delivers the code, on the web or in an app, it rests on one thing: the code that does the encrypting, which your device receives from us, has to be genuine. If that code were tampered with, data could be read before it is encrypted. Keeping that from happening, holding our code and systems trustworthy against both outside attack and our own mistakes, is the security responsibility we take most seriously.
How we hold up that responsibility, in practice:
- No third-party analytics, trackers, advertising, or marketing cookies, ever. The less outside code on the page, the less that could ever be turned against you. Permanent, not a setting.
- A strict content policy that limits where data can go. The app loads its code from our own systems and is only permitted to send data back to them, so even a script that somehow slipped in could not quietly ship your information elsewhere.
- Dependencies pinned and kept clean. Every third-party building block is locked to a known version, held at zero known vulnerabilities, and watched by automatic alerts; we don’t add new ones for small conveniences, that is how a poisoned package is caught before it ships.
- The encryption is small, isolated, and documented. It lives in two short files and uses your device’s own built-in AES, so the part that matters most can be audited directly rather than hunted for in a haystack.
- We hold as little as possible. Everything sensitive stays in the vault we can’t read; only the minimum account details are in the clear. Less held, less at stake.
If you turn on fingerprint unlock in the app, your fingerprint is handled entirely by your phone — we never see, store, or receive it. It only releases your vault key from your phone’s secure chip; the key never leaves the device or reaches us.
What we hold unencrypted, because we must: your email address (for login), your IP address and sign-in times (security logging), your subscription status (for billing), the region you choose, and your account creation date, plus a few operational records like team membership and security logs, set out in full in the privacy policy. None of it is the content of your vault.
How the encryption works
We use the well-established vault model, the standard approach for encrypted personal data. One per-user encrypted JSON blob holds every sensitive field. The vault is encrypted with a 256-bit master key generated on your device. The master key is wrapped twice:
- Once with a key derived from your password.
- Once with a key derived from your one-time recovery key.
Either path can unlock the vault. Losing both is permanent, there is no other recovery path because there cannot be one without us being able to read your data.
The cryptographic choices
- Password-to-key derivation: Argon2id, m=19 MB, t=2, p=1, 32-byte output. OWASP 2023 first-tier recommendation. Memory-hard by design, which means a GPU or ASIC cluster cannot precompute attacks the way it can against PBKDF2 or bcrypt. Derivation runs in a fraction of a second, around 30 ms on a modern laptop, still well under a second on a phone. It is the memory-hardness, not any wall-clock delay, that makes a stolen vault costly to attack, and your password strength matters most of all.
- Symmetric encryption: AES-256-GCM via the Web Crypto API. Authenticated Encryption with Associated Data (AEAD), every ciphertext carries a 128-bit authentication tag. Tampering produces a clean cryptographic failure rather than silently corrupted output. The Web Crypto API is native to your device and audited, the AES encryption itself runs there, not in third-party code. The one library on the path is the Argon2id password-hashing step, which uses hash-wasm, a widely used open-source WebAssembly implementation; the AES layer stays native.
- Key wrapping: the master key itself is encrypted twice, once under the password-derived key, once under the recovery-key-derived key. Either path can unwrap the master key. Password change re-wraps only the password copy; the encrypted vault payload stays intact and the operation is fast.
- Random values: 16-byte salts and 12-byte fresh IVs per encryption, every encryption gets a new nonce so even identical plaintexts produce different ciphertexts. Sourced from
crypto.getRandomValues(a CSPRNG, cryptographically secure pseudo-random number generator), never fromMath.random. - Recovery key: 256 bits of CSPRNG output, formatted as 16 groups of 4 hex characters separated by dashes. Same security level as the master key.
Defense in depth
Encryption is the strongest layer, but it is not the only layer. Each defense below is independent, an attacker who breaches one still has every other layer to get through.
- Application layer: end-to-end encryption with Argon2id + AES-256-GCM, as described above.
- Transport layer: TLS 1.3 in transit, enforced via HSTS with
preload,includeSubDomains, and a 2-yearmax-age. Browsers refuse to talk to RainWillCome over plain HTTP. - Browser sandbox: a strict Content Security Policy blocks third-party scripts except our bot-protection provider (Cloudflare Turnstile).
frame-ancestors 'none'andX-Frame-Options: DENYprevent clickjacking.Cross-Origin-Opener-PolicyandCross-Origin-Resource-Policyisolate the page from Spectre-class side-channel attacks. - Database layer: Postgres row-level security (RLS) prevents one user's row from being read by another even if the application layer were bypassed. The encrypted vault sits inside an RLS-protected row.
- Code path: no analytics, no fingerprinting, no third-party tracking pixels. The only third-party script we load is our bot-protection provider (Cloudflare Turnstile), on the sign-in and sign-up pages. Everything else came from the RainWillCome codebase under our direct control.
- Operational layer: the master key lives only in
sessionStoragefor the duration of your tab. Closing the tab clears it. Logging out clears it. There is no persistent “remember me” for the master key.
What we protect against
- Database breach. If our database were stolen tomorrow, the attacker would have a list of email addresses and encrypted blobs. No questionnaire answers. No plans. No roster.
- Insider threat. The RainWillCome team holds no decryption keys. Engineers, support staff, and founders cannot read user data. This is enforced by the architecture, not by policy alone.
- Subpoena and law-enforcement requests. If we receive a legal order, we can produce only what we have, email and subscription metadata. We have no decrypted user data to hand over because we never had it.
- Casual snooping. Row-level security in our database stops cross-user reads at the database layer, in addition to the encryption above.
What we do not protect against
- A compromised device. Anything on the device that can read sessionStorage can see the unlocked master key while you are signed in. Standard practice: do not run unknown code in your browser, keep your device updated.
- A weak password. Argon2id slows brute force but cannot defend a password your attacker can guess in five tries. Use a long, unique password, preferably from a password manager.
- Targeted nation-state attacks. If a sophisticated attacker has compromised your device hardware, browser, or network, no platform, including this one, can fully protect you. The threat model here is the realistic one for households, not the maximum-paranoia one.
Code review on request
The cryptographic primitives live in lib/crypto.ts and the vault model in lib/vault.ts. The source is not currently published as open source, that is a decision we want to make deliberately, not by default. Until then, anyone with a credible security-research background can request read access to the relevant files for audit purposes.
We have not yet commissioned an independent third-party audit. That is on the roadmap once budget allows.
Reporting a vulnerability
If you find a security issue, please report it directly rather than disclose it publicly. We will credit you in a public hall-of-fame on this page once the issue is fixed and a reasonable disclosure window has passed. We do not currently offer cash bounties.
Report path: open an issue at the repository linked above marked with the security label, or email the address listed in the legal disclaimer.
Warrant canary
Our warrant canary, a dated statement that we have received no secret legal process and no order to weaken the encryption, and that we have built no key-escrow or “ghost participant” mechanism, is maintained in one place so it cannot drift: the transparency report. It is refreshed with each edition. If that statement disappears or stops being updated, treat it as a signal.
If affiliate links arrive later
The RainWillCome team does not earn money from any of the products or training we currently recommend on the “Our shelf it” page. If that ever changes, we will say so clearly on every item that earns us money, and the alternatives that do not earn us money will stay listed alongside.