What changed, and why it matters
This commit fixes a coding guideline violation in the BitBox02 factory setup code. A 32-byte buffer that receives output from a Rust function was not initialized to zeroes before use. The accompanying documentation now explicitly requires such initialization. The actual security impact is limited because the buffer is immediately filled by a hash function if it succeeds, and failure paths in this specific factory-setup function appear to abort rather than leak the uninitialized buffer. However, uninitialized stack memory is a well-known source of bugs, so the change is defensive.
Treat as a low-risk hardening fix. Review other call sites of rust_util_bytes_mut to confirm they follow the new zero-initialization guideline. No urgent security response is indicated by the diff alone, but the change should be included in the next firmware release.
Security signals we found
Uninitialized stack buffer used as output buffer for Rust/C FFI call
Defensive zero-initialization added to prevent use of stale stack data on error or partial write paths
Project coding guidelines updated to mandate zero-initialization for rust_util_bytes_mut buffers
Evidence from the diff
In src/factorysetup.c, _api_msg() declared uint8_t candidate_identifier[32]; without initialization and passed it to rust_secp256k1_pubkey_identifier() via rust_util_bytes_mut(). The Rust function is expected to write a SHA-256 identifier into the buffer. AGENTS.md was updated to state that C buffers passed to rust_util_bytes_mut must always be zero-initialized. The patch initializes the buffer with = {0}. The diff alone does not show that the old code led to an exploitable information leak; it only shows an uninitialized stack variable being fixed. The function is part of factory setup, not normal wallet runtime, reducing exposure.
Changed components
src/factorysetup.c:_api_msg()AGENTS.md coding guidelinesRust/C FFI buffer handling (rust_util_bytes_mut)Inspect captured patch +3 / −1
### AGENTS.md
@@ -122,6 +122,8 @@ screenshots, and flag hardware requirements. Wait to squash until reviews conclu
- when converting C code to Rust code, make the Rust code idiomatic, not a 1:1 rewrite.
- when exposing Rust functions to C using extern "C", use util::bytes::Bytes and
util::Bytes::BytesMut ot pass in buffers and write to out buffers.
+ Always initialize C buffers passed to `rust_util_bytes_mut` to zeroes, e.g.
+ `uint8_t buf[32] = {0}`.
- when using Zeroizing<...> for buffers, use Zeroizing<Vec<u8>>. For other sensitive data, use
Zeroizing<Box<...>>.
- when wrapping C functions, always use a '-sys' crate for the bindings, make it safe idiomatic
### src/factorysetup.c
@@ -746,7 +746,7 @@ static void _api_msg(const uint8_t* input, size_t in_len, uint8_t* output, size_
const uint8_t* root_pubkey = NULL;
for (size_t pubkey_idx = 0; pubkey_idx < sizeof(_root_pubkey_bytes) / ROOT_PUBKEY_SIZE;
pubkey_idx++) {
- uint8_t candidate_identifier[32];
+ uint8_t candidate_identifier[32] = {0};
// Identifiers remain SHA-256 of the uncompressed key, as used by the host.
if (!rust_secp256k1_pubkey_identifier(
rust_util_bytes(_root_pubkey_bytes[pubkey_idx], ROOT_PUBKEY_SIZE),Why this scored 41/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.