fix: seed signer messages are wrongly splited
What changed, and why it matters
This commit fixes how the Keystone hardware wallet parses 'signmessage' QR code requests from SeedSigner. Previously, the code split the message at every colon, so a message containing colons would be cut off and only the first part would be signed. Now it splits only at the first colon and rejects empty messages. A truncated or altered message could lead to signing something different from what the user intended, which is a security concern for message signing workflows.
Review whether other QR protocol parsers in the same file or elsewhere use split(':') or similar delimiter splitting on attacker-influenced payloads, and apply split_once or equivalent boundary-safe parsing. Confirm that downstream signing logic validates message length and format before user approval.
Security signals we found
Input parsing boundary error: split(':') truncated payload at embedded delimiters
Message-integrity risk: signed message could differ from user-intended content
Missing validation: empty message was accepted before patch
Patch is narrowly scoped to a single parsing function
Evidence from the diff
The Rust function parse_qrcode_text in rust/rust_c/src/common/qrcode/mod.rs previously used value.split(‘:’) to separate the ‘signmessage’ header from the payload. Because split returns an iterator that consumes all colon-delimited segments, any colon characters inside the actual message were discarded along with everything after the first colon. The patch replaces this with value.split_once(‘:’), which performs a single split at the first colon, preserving the rest of the message. It also adds an explicit check for an empty message and returns an UnsupportedTransaction error in that case.
Changed components
rust/rust_c/src/common/qrcode/mod.rsparse_qrcode_text functionSeedSigner signmessage QR code handlingInspect captured patch +7 / −4
diff --git a/rust/rust_c/src/common/qrcode/mod.rs b/rust/rust_c/src/common/qrcode/mod.rs
index 3e3f150..8c0464b 100644
--- a/rust/rust_c/src/common/qrcode/mod.rs
+++ b/rust/rust_c/src/common/qrcode/mod.rs
@@ -30,10 +30,13 @@ pub unsafe extern "C" fn infer_qrcode_type(qrcode: PtrString) -> QRProtocol {
pub unsafe extern "C" fn parse_qrcode_text(qr: PtrString) -> Ptr<URParseResult> {
let value = recover_c_char(qr);
if value.to_lowercase().starts_with("signmessage") {
- let mut headers_and_message = value.split(':');
- let headers = headers_and_message.next();
- let message = headers_and_message.next();
- if let (Some(headers), Some(message)) = (headers, message) {
+ if let Some((headers, message)) = value.split_once(':') {
+ if message.is_empty() {
+ return URParseResult::from(RustCError::UnsupportedTransaction(
+ "Invalid seed signer message format".to_string(),
+ ))
+ .c_ptr();
+ }
let mut pieces = headers.split_ascii_whitespace();
let _ = pieces.next(); //drop "signmessage"
let path = pieces.next();
Why this scored 46/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.