Blockstream / Blockstream/Jade
Seed entropy and QR icon data not zeroized in mnemonic QR-export flow
- Dominant language
- C
- Stars
- 496
- Forks
- 127
- PR merge metrics
- No merged PRs in 30d
Description
## Summary
In `mnemonic_export_qr()` (`main/process/mnemonic.c`), the raw mnemonic entropy (i.e. the seed) is converted into a CompactSeedQR and displayed as on-screen icons. Unlike every other seed-handling path in the codebase, none of this data is zeroized:
- `uint8_t entropy[BIP32_ENTROPY_LEN_256]` (line 83) and `qrbuffer[96]` (line 91) are stack buffers holding the raw seed, and are never wrapped in `SENSITIVE_PUSH`/`SENSITIVE_POP`.
- The QR icons (`icons[i].data`, `qr_overview.data`, allocated with `JADE_CALLOC_PREFER_SPIRAM` in `qrcode.c`) encode the full seed, but are released with plain `free()` — `qrcode_freeIcon()` (`main/qrcode.c:1076`) performs no zeroization.
After the export flow the seed therefore remains readable in freed heap and on the stack. This contradicts the hardening added in 1.0.40 ("Clear secrets from memory more diligently after UI display") and the `SENSITIVE_PUSH`/`SENSITIVE_POP` discipline used everywhere else (e.g. `mnemonic_new()`, `get_bip85_mnemonic()`, `import_compactseedqr()`).
Related: #180
## Suggested fix
- Wrap `entropy` and `qrbuffer` with `SENSITIVE_PUSH`/`SENSITIVE_POP`.
- Zeroize icon data before freeing — e.g. `wally_bzero(icon->data, qrcode_get_icon_data_size(icon->width, icon->height))` inside `qrcode_freeIcon()` (would need `#include ` added to `qrcode.c`), and the same for `icons[i].data` before `free()` in the cleanup path (`mnemonic.c:225-229`).
## Verification
Confirmed still present on current `master` (as of 2026-08-04): `main/process/mnemonic.c:83` and `main/qrcode.c:1076` unchanged. `qrcode_freeIcon()` has a single caller, so the fix has no impact outside the QR-export flow.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.