Security of a crypto wallet for a baby
The 24 words are the whole wallet, so the site is built around one rule: they are made in your browser, shown once, and never leave it. Here is how, and where that rule stops protecting you.
What happens on your device
- Randomness. The words come from 256 bits of your browser's
crypto.getRandomValues, the operating system's secure generator, turned into BIP39 words by the audited@scure/bip39library. There is no fallback: a browser without that generator, or one that hands back a constant, a repeating pattern or the same draw twice, gets an error instead of a card. - Addresses. Bitcoin (BIP84,
m/84'/0'/0'/0/0), Ethereum (m/44'/60'/0'/0/0) and Solana (SLIP-10,m/44'/501'/0'/0') are derived in the page with@scure/bip32and@noble/curves, and the tests hold them to the published BIP39, BIP32, BIP84 and SLIP-10 vectors and to a second, independent implementation. The seed and private keys are zeroed as soon as the addresses are known. - Shown once. The words are put in the page only on the gift-card step and taken out the moment you leave it. They are never written to local storage, IndexedDB, a cookie, the address bar, a cache or the clipboard — there is no copy button for them.
- No translation, spelling or grammar service. Browser translation sends page text to a server, outside the page's security policy, so the card and the check fields are marked to be left untranslated, and the check fields turn off autofill, spell-check and grammar extensions. Airplane mode stops all of these for certain.
- Checking the paper. The check asks for three words by default, which proves the paper exists; checking all 24 proves every word is right, and is worth the two minutes.
- What is kept. This browser keeps the baby's name, the date and the three public addresses, so the balance page can find them. Clear the site's data and they are gone.
What reaches the network
- The wallet and gift pages make no request beyond their own files. Their security policy (
connect-src 'none') forbids one, so even a bug could not send the words. - The gift link carries the name and addresses after
#. Browsers never send that part to a server, and the site'sReferrer-Policy: no-referrerkeeps the page address out of anything else. - The balance page is the only one allowed to connect anywhere, to three public servers it names, and only when you press Check balances. They see the addresses, never the words.
- Nothing else. No analytics, no cookies, no fonts or scripts from other sites, and the pages cannot be framed by another site.
What this site cannot protect against
- A compromised device. Malware, a screen recorder or a browser extension that can read pages would see the words as you do. Use a device you trust, in a private window with extensions off, and keep airplane mode on while the card is on screen.
- A compromised copy of the site. If someone changed the files this site serves, a changed page could make words that are not random, or try to send them. The security policy arrives from the same server, so it cannot help in that case; airplane mode stops sending, but not bad randomness. The defence is to run a copy you have checked.
- Copies you make yourself. A photo, a PDF, a cloud printer or a note on your phone is a copy of the words that this site cannot reach or erase.
- Screens and memory. A screenshot, a phone's app-switcher snapshot or screen sharing copies what is on screen. The words also stay in the browser's memory until the tab is closed, because a script cannot erase text from it: close the tab when you are done.
- A faked gift link. The gift page shows what its link says. A relative who got the link from someone else should check it with the family.
Running it offline from a saved copy
- On a device you trust, open the front page and save it before you make a wallet, never with a card on screen (a saved page keeps what is showing): File › Save Page As, then Webpage, Complete. Keep the saved file and its folder on a USB stick, or on the computer you will use.
- Better still, build it yourself from the source:
npm ci,npm test,npm run build, then opendist/index.html. The script is a plain file, so it runs from your disk with no server. - Turn the network off — airplane mode, Wi-Fi off, cable out — and open the saved page. Make the wallet, write the words down, check them, and close the window before you turn the network back on.
The gift link a saved copy makes points at address.baby, like the live site's, because that is where relatives open it.
Libraries
The page's code is the site's own plus these libraries, pinned to exact versions and bundled into the site's files at build time; nothing is loaded from elsewhere:
@noble/curves@2.4.0— secp256k1 and ed25519 public keys@noble/hashes@2.4.0— SHA-256, SHA-512, RIPEMD-160, Keccak-256, HMAC@scure/base@2.4.0— bech32, base58 and their checksums@scure/bip32@2.4.0— BIP32 key derivation for Bitcoin and Ethereum@scure/bip39@2.4.0— the 24 words: entropy to BIP39 words and words to seedqrcode-generator@2.0.4— the QR codes, drawn in the pageesbuild@0.28.2— bundles them at build time; it does not ship