Skip to content

Security: allinbits/picowallet

Security

SECURITY.md

Security

A standing security review of PicoWallet as a validator-signing solution for Tendermint-class chains. Compares against the dominant alternatives, names the realistic threat model, and is honest about both the architectural advantages and the categorical gaps.

This document assumes the production configuration: PICOWALLET_M9_OTP_BIND on (per-device OTP secret mixed into the Argon2id KEK input) and bootrom-enforced signed firmware. Both are required for any deployment past testnet.

To report a security issue, see Reporting vulnerabilities at the bottom of this document.


What PicoWallet is

A hardware validator-signing device for Tendermint-class chains (cosmos-sdk, gno.land) built on the RP2350. The firmware is split into a Secure / Non-Secure pair via ARM TrustZone-M. The Secure image owns the master mnemonic, per-slot overrides, OTP-bound KEK derivation, HWM ratchet, sign operations, flash mutations, e-paper UI, and button input. The Non-Secure image runs USB, lwIP, the privval / SecretConnection / amino parsers, and the REPL. NS reaches Secure only through the typed veneer ABI in firmware/src/os/secure_api.h.


What it's competing with

Stack Where keys live Trust unit Cost Track record
TMKMS + YubiHSM2 YubiHSM dedicated chip Closed firmware on a CC EAL5+ HSM ~$650 + host Years; majority of cosmos validators
TMKMS + softsign Encrypted disk on the signer VM Linux + TMKMS process ~$0 + host Common but table-stakes only
AWS Nitro Enclaves Enclave memory KVM + AWS hypervisor + attestation Pennies/hr Production at several funds
Horcrux Sharded across N MPC nodes Threshold Ed25519 N × host Production at Strangelove, Coinbase
Ledger / hw-wallet Secure Element (ST31/33) CC EAL5+, closed $80–$300 Massive — but per-tx UX, wrong shape for validators
PicoWallet RP2350 TrustZone-M Secure image Open firmware, commodity Cortex-M33 + bootrom-signed boot + OTP-bound KEK ~$15 BoM Pre-prod, single author, no external audit

That last column is the gap the rest of this document explores.


Threat model

Defended

Remote compromise of the signer host. NS is the entire network stack — lwIP, TinyUSB, REPL, SC handshake, privval parser — and is treated as adversarial-controllable. Keys live in Secure RAM; NS reaches them only through the veneer ABI. RCE in NS does not yield the seed.

Double-sign across reboots, power loss, network split-brain. The HWM strict-advance ratchet lives inside the Secure image and is fused with the signature in s_sign_and_advance: Secure persists the new (height, round, type) tuple to flash before computing the signature. NS cannot replay an old tuple; HWM is not a software file above the signing oracle (as it is in TMKMS+YubiHSM). The chain_id is bound per slot — sign requests whose canonical bytes claim a different chain_id than the slot's are refused inside Secure before the ratchet advances.

Cross-chain key reuse. Each slot carries an independent (chain_id, BIP-44 derivation path, optional per-slot mnemonic or raw key). A configuration error or compromised NS cannot cause one chain's key to sign for another.

Cold-stolen device. OTP binding eliminates the offline brute-force attack. The Argon2id KDF input is OTP_secret || PIN. The per-device OTP secret is burned at first boot, ACCESSCTRL_OTP locked at Secure entry, and is unreadable across the NS/Secure boundary. An attacker who extracts the flash blob without the chip has no path to derive the KEK — the OTP secret is part of the secret and the chip is part of the path. PIN entropy stops being load-bearing for this attack; even a 4-digit PIN survives it.

Stolen-and-returned firmware swap (BOOTSEL → drop malicious UF2). Bootrom rejects unsigned firmware. The attacker cannot replace the image with a key-logger and return the device unnoticed.

Supply-chain pre-flash. Same closure — a tampered chip won't boot a signed image.

NS persistence across reboots. NS can write its own flash region, but bootrom won't boot a modified image on next reset. Persistence requires avoiding reboots, which bounds dwell time.

Operator consent at provisioning time. PIN entry, mnemonic display/restore, slot setup, and factory reset all run in Secure-driven UI on a Secure-only e-paper. NS cannot fake an "OK" screen or pretend a wipe didn't happen.

Not defended

NS-RCE → traffic manipulation and denial of service. RCE in NS doesn't get the seed but gets:

  • Denial of sign requests (missed blocks, jailing risk)
  • Visibility into traffic timing for every signature
  • Ability to route signatures to attacker-controlled peers (partially mitigated by SC pubkey pinning per slot, but only if the operator configured it)
  • 10 PIN-attempt window before the device wipes itself

The attacker can't sign at leisure — each signature still requires an operator-initiated sign request and the HWM ratchet only moves forward. But signature content is influenced by what NS chooses to present.

Block-content visibility limit (structural). NS canonicalizes the bytes Secure signs. Secure parses (type, height, round, chain_id) for HWM and binding checks, but it cannot inspect the block hash encoded inside the canonical bytes. A compromised NS can show the operator "vote on block X" via the screen while signing "vote on block Y" within the same (height, round) tuple. The HWM ratchet still prevents double-signing across (h, r, type), and chain_id binding still prevents cross-chain misuse — but within a chain and a given consensus slot, NS chooses what gets signed.

This limit applies to every signer that doesn't run a full consensus node: TMKMS, YubiHSM, AWS Nitro, Horcrux. It is structural, not implementation.

Powered-theft + warm-reset for BSS retention. If an attacker grabs the device while running with secrets loaded (insider scenario, data-center theft, tamper-while-operational), they can warm-reset and read Secure BSS before the boot path clears it. This is the only powered-device attack that survives the 10-attempt PIN counter. The risk is bounded to "device was running when stolen" — power-off-then-steal clears RAM in microseconds.

TRNG provenance at provisioning. The RP2350 TRNG is a single-source ring oscillator. A biased or weak TRNG at the moment of mnemonic generation produces a guessable master seed, and OTP binding doesn't help — the seed itself is bad. We do not currently mix bootrom RNG, button-press jitter, or other entropy sources. One-shot, irreversible. Only applies to GENERATE flow; RESTORE imports entropy generated elsewhere.

Side-channel hardness on commodity Cortex-M33. The chip has no anti-tamper mesh, no constant-power arithmetic, no masked operations. Power analysis on Argon2id during PIN unlock is bounded by the 10-attempt counter, so the PIN gate caps the trace budget. But once unlocked, every signature is potentially observable by an insider with a power probe on the rails. Recovering key material from a small number of post-unlock traces is plausible for an attacker with bench equipment and access. YubiHSM and Ledger SE have countermeasures; Cortex-M33 doesn't. Nation-state-or-insider class.

Loss of the device. Single device, no threshold. Recovery via mnemonic re-import on a fresh device, with downtime measured in operator response time. Horcrux solves this; PicoWallet on its own does not.

Remote attestation. Bootrom-signed firmware ensures the device booted a signed image, but there is no chain-of-trust from a specific device identity to the chain operator. A silently-swapped PicoWallet (same firmware, attacker's mnemonic restored from the operator's paper backup) is not detectable from the network. The operator would notice from the on-device pubkey display, but the chain operator cannot. YubiHSM has Yubico-signed device-attestation certs; Nitro produces attestation documents; PicoWallet has neither.

Certification, audit pedigree, track record. Zero. Open-source firmware that's been self-reviewed is a different artifact than a CC EAL5+ device with Common Criteria documentation and a vendor on the hook. For insurance, compliance audit, and large-TVL risk acceptance, this matters categorically.

Nation-state physical attack. Decap + SEM readout of OTP rows, fault injection during ACCESSCTRL programming pre-BXNS, voltage glitching during a signing operation. Real, irrelevant for the vast majority of realistic threat models, not addressable on commodity Cortex-M33 regardless of firmware quality.


Where PicoWallet genuinely wins

1. HWM lives inside the trust boundary, fused with the signature. TMKMS+YubiHSM splits this: TMKMS holds the HWM file, YubiHSM signs anything you ask it to. A compromised TMKMS process can produce duplicate signatures by lying to the HSM about what height is being signed. PicoWallet's Secure side rejects this at the veneer — the ratchet advance is atomic with the signature, both inside Secure.

This is the only signing failure that has actually slashed validators in production at meaningful TVL. It's the one category where PicoWallet's architecture is structurally better than the dominant alternative, not just different.

2. Per-chain mnemonic isolation. TMKMS+YubiHSM gives each chain a key slot, but the same root entropy backs all keys unless you provision multiple HSMs. PicoWallet lets each slot carry its own BIP-39 mnemonic or imported raw key, so a leak of slot N doesn't compromise slot M. The per-chain BIP-44 derivation path provides a softer layer of separation for slots that share the master mnemonic.

3. Operator-visible UI inside the trust boundary. YubiHSM is opaque — the operator sees whatever their host says. PicoWallet shows the mnemonic, PIN prompt, slot status, error counters, and factory-reset confirmation on a screen the Secure image owns directly via Secure-only SPI. The factory-reset gesture is on-device, not "ssh in and rm -rf."

4. Open firmware, reviewable threat boundary. ~17k lines of code total, ~8k excluding third-party. The trust boundary is one header (firmware/src/os/secure_api.h) and one file (firmware/m9/veneers.c). YubiHSM2's firmware is closed; you trust Yubico. PicoWallet you can audit yourself.

5. Cost. ~$15 BoM (Pico 2 + W5500 + e-paper + buttons + box) vs ~$650 for a YubiHSM. For a small validator or testnet operator, this is the difference between "deployable" and "not deployable."

6. Strong KDF at rest. Argon2id with 64 KiB memory and t=3 passes, bound to the OTP secret. The attacker needs the chip itself to even attempt a derivation. YubiHSM uses PIN comparison directly; PicoWallet adds memory-hard work on top of chip-bound KDF.


Where PicoWallet honestly loses

1. No certification, no audit, no production track record. Categorically. "Self-reviewed open source" is a different artifact than CC EAL5+. For compliance shops, insurance, and any custodian making formal risk decisions, this is a blocker regardless of how good the architecture is. YubiHSM ships with paperwork; PicoWallet ships with a README.

2. Single device, no threshold. Horcrux can lose 1 of 3 nodes and keep signing. PicoWallet loses 1 of 1. Validators with uptime SLAs need multiple devices behind a sentry node with manual cutover, or PicoWallet integrated as a Horcrux signer node — neither integration exists today.

3. Side-channel hardness on commodity Cortex-M33. TrustZone-M is isolation, not hardening. The Secure code runs on the same cache, same power rails, same EM emissions as NS. Power analysis on signing operations by an insider with bench equipment is plausible. Bounded for the PIN unlock by the 10-attempt counter; unbounded for post-unlock signing.

4. NS-side attack surface. Every CVE in lwIP, TinyUSB, or our SC handshake is RCE in NS. It doesn't get keys but gets DoS, traffic-timing visibility, peer routing manipulation, and 10 PIN guesses before wipe. The attack surface is large by validator-signer standards — most HSMs don't expose a TCP stack.

5. Block-content visibility limit. Structural; applies to every signer. PicoWallet is no worse than the alternatives but is also no better.

6. H3 BSS retention. Powered-theft + warm reset can extract Secure RAM before BSS clears. Documented in docs/H3_SECURE_BSS_REDESIGN.md with three implementable redesigns; none are shipped. Bounded to insider / powered-theft scenarios.

7. TRNG provenance at provisioning. Single-source ring oscillator. One-shot decision at first boot determines the master mnemonic forever. RESTORE flow bypasses this; GENERATE flow doesn't.

8. No remote attestation. Operator can prove their device is running signed firmware to themselves (on-device display) but cannot prove device identity to the chain operator. Silent device swap with re-imported mnemonic is undetectable from the chain side.


When PicoWallet is the right choice

  • Testnet / devnet validators. HSM is overkill, threshold is overhead, you want operator-visible audit of every sign.
  • Hobbyist or small mainnet validator (sub-$1M TVL). Realistic threats are closed by OTP + signed firmware + HWM-in-Secure. Single-device fragility is an operational risk, not a security risk at this scale.
  • Multi-chain operator who needs per-chain key isolation. Independent mnemonics per slot is unique to PicoWallet at this price.
  • Security team requires auditable firmware. Closed-source HSM firmware is a non-starter; PicoWallet's threat boundary is one header.
  • Mid-size mainnet validator as a Horcrux signer node. Threshold via Horcrux + trust-boundary + per-chain + auditability from PicoWallet. This composition is defensible on real TVL.

When PicoWallet is the wrong choice

  • Large validator with significant TVL. "No audit, no track record" is a categorical gap. Use YubiHSM2 + TMKMS + Horcrux until that gap closes.
  • Compliance shop needing FIPS / CC / SOC2 paperwork. Not happening with commodity Cortex-M33 regardless of firmware quality.
  • Threat model includes nation-state physical attack. Decap + SEM defeats OTP binding. Use a real Secure Element.
  • Uptime SLA tighter than mean-time-to-replace-device. Single device, no HA. Run Horcrux or run two devices behind a sentry with manual cutover.
  • Standalone deployment without Horcrux behind it for anything more than testnet. The fragility is operational, but operational fragility on a validator is a security issue at scale.

Concrete risks worth addressing before production

In rough priority for any deployment past testnet:

  1. Implement H3 BSS retention mitigation. Pick one of the three redesigns in docs/H3_SECURE_BSS_REDESIGN.md and ship it. Closes the only powered- attack vector that survives the PIN counter.
  2. TRNG entropy mixing at provisioning. Mix bootrom RNG + ring oscillator
    • button-press jitter into master mnemonic generation. One-shot, irreversible if missed.
  3. Lightweight attestation surface. Sign a (device-pubkey, firmware-hash) tuple at boot, expose via REPL. Not a Yubico-style cert chain, but enough for "is this the device I provisioned?"
  4. Horcrux integration. Solves single-device fragility and adds defense in depth. A compromised PicoWallet in a 2-of-3 threshold cannot unilaterally sign.
  5. Independent audit. Send to Trail of Bits, NCC, or Ledger Donjon once the above land. The H3 finding and the boundary design are what's worth putting in front of someone who breaks hardware wallets professionally.
  6. Side-channel hardening pass on post-unlock signing. Lower priority than the above. Constant-time SLIP-10 derivation and Ed25519 signing on the hot path.

Bottom line

PicoWallet's architecture has two genuine improvements over the dominant TMKMS+YubiHSM stack: HWM fused with the signature inside the trust boundary, and per-chain mnemonic isolation. The first one matters because HWM bugs are the actual failure mode that has slashed validators in production. The second one matters because multi-chain operators currently have no clean answer.

The realistic-attacker threat picture (steal device, take it home, brute force) is closed by OTP binding and bootrom-signed firmware. The remaining gaps are categorical: certification, audit pedigree, track record, threshold HA, remote attestation, side-channel hardness, and a structural NS-side attack surface that bounds RCE to DoS and traffic manipulation rather than key extraction.

The defensible deployment story:

  • Hobbyist / testnet / small mainnet: standalone, defensible.
  • Mid-size mainnet: behind Horcrux, as one signer node of three. Defensible.
  • Large validator / compliance: not yet. YubiHSM + TMKMS until track record exists.
  • Nation-state threat model: not a candidate; use a real Secure Element.

The architectural decisions are right. The categorical gaps — certification, audit, track record, threshold — are not software problems and won't close with more firmware work. They close with audit budget, deployment time, and a Horcrux integration. None of those are technically blocked; all of them are unblocked work.


Reporting vulnerabilities

If you find a security issue in PicoWallet:

  • For non-sensitive issues (build/UX bugs that have security implications but are not exploitable), open a GitHub issue at https://github.com/allinbits/picowallet/issues.
  • For sensitive issues (anything that could expose key material, bypass the HWM ratchet, defeat the TZ boundary, or be exploited against a deployed device), please disclose privately first. Open a draft security advisory via GitHub's "Report a vulnerability" workflow on the repository's Security tab.

Coordinated disclosure: please give at least 30 days for a fix before public disclosure. We will credit reporters in the advisory unless they prefer otherwise.

There aren't any published security advisories