What changed, and why it matters
This commit fixes a bug in the rust-bitcoin library where a specific function used to verify Bitcoin signed messages could crash the program. The crash could be triggered by feeding it a carefully crafted 88-character base64 string that decoded to 66 bytes instead of the expected 65 bytes. The fix adds proper length checks so the function returns a clean error instead of panicking, and also rejects 64-byte results that were previously silently accepted.
Treat this as a security-hardening fix with denial-of-service relevance. Reviewers should verify that all callers of `from_base64` now handle `InvalidLength` correctly, confirm no other base64 decode sites in the crate use similarly sized buffers without length checks, and consider whether this bug warrants a CVE or advisory if untrusted input can reach this function in production deployments.
Security signals we found
Panic/crash on malicious input (denial-of-service vector)
Incorrect length validation of base64-decoded signature
Potential silent acceptance of malformed 64-byte signatures
Missing bounds check before using fixed-size buffer
Evidence from the diff
In bitcoin/src/sign_message.rs, the from_base64 method of MessageSignature previously assumed any 88-character base64 string would decode to exactly 65 bytes. However, base64 encoding of 66 bytes can also produce an 88-character string (e.g., 88 ‘A’ characters decode to 66 zero bytes). The old code wrote into a fixed 65-byte array, causing an out-of-bounds panic when 66 bytes were decoded. The patch enlarges the temporary buffer to 66 bytes, records the actual decoded length, rejects anything other than 65 bytes with InvalidLength, and then passes only the first 65 bytes to from_byte_array. It also implicitly fixes the case where 64 bytes were decoded and previously passed through, likely to be caught later by secp256k1 parsing but now surfaced as a clearer length error.
Changed components
bitcoin/src/sign_message.rsMessageSignature::from_base64Bitcoin message signing/verificationInspect captured patch +9 / −3
diff --git a/bitcoin/src/sign_message.rs b/bitcoin/src/sign_message.rs
index 9e8c2d83..35a1b05a 100644
--- a/bitcoin/src/sign_message.rs
+++ b/bitcoin/src/sign_message.rs
@@ -132,11 +132,17 @@ mod message_signing {
if s.len() != 88 {
return Err(MessageSignatureError::InvalidLength);
}
- let mut byte_array = [0; 65];
- BASE64_STANDARD
+ let mut byte_array = [0; 66];
+ let decode_len = BASE64_STANDARD
.decode_slice_unchecked(s, &mut byte_array)
.map_err(|_| MessageSignatureError::InvalidBase64)?;
- Self::from_byte_array(&byte_array).map_err(MessageSignatureError::from)
+ if decode_len != 65 {
+ return Err(MessageSignatureError::InvalidLength);
+ }
+ let exact_bytes = byte_array[..65]
+ .try_into()
+ .expect("exactly 65 bytes exist in byte_array slice");
+ Self::from_byte_array(&exact_bytes).map_err(MessageSignatureError::from)
}
/// Converts to base64 encoding.
Why this scored 62/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.