fix(trezor-client): send empty passphrase for standard wallets
What changed, and why it matters
This commit fixes a bug in the Trezor client library where users with a standard wallet (no passphrase) were still being prompted to enter a passphrase on their Trezor device. The fix ensures that for standard wallets, the client replies with an empty passphrase instead of incorrectly asking the device to handle it. This is a usability and workflow bug rather than a direct theft-of-funds vulnerability, but it could cause confusion or lead users to enter an unintended passphrase.
Review related host-side passphrase logic to ensure no other paths incorrectly set on_device=true, and verify that empty passphrase handling matches Trezor protocol expectations. Consider whether this bug could have been exploited in social-engineering or UI-confusion scenarios.
Security signals we found
Incorrect handling of passphrase request flow in hardware wallet client
Potential UI confusion or user coercion via unexpected on-device passphrase prompt
Fix aligns host-side behavior with standard wallet semantics
Evidence from the diff
In rust/trezor-client/src/client/common.rs, the handle_interaction function previously called req.ack(!on_device) for all PassphraseRequest responses. When on_device was false (meaning the host should supply the passphrase), it would still pass true to ack(), which tells the Trezor to prompt on-device. The patch changes this so that if req.on_device() is true, it calls ack(true); otherwise, it calls ack_passphrase(String::new()), sending an empty passphrase for standard/non-passphrase wallets. This corrects the protocol flow so the device does not prompt when no passphrase is configured.
Changed components
rust/trezor-client/src/client/common.rsTrezor client library passphrase handlingInspect captured patch +4 / −3
diff --git a/rust/trezor-client/src/client/common.rs b/rust/trezor-client/src/client/common.rs
index 897f8497..0fbb6740 100644
--- a/rust/trezor-client/src/client/common.rs
+++ b/rust/trezor-client/src/client/common.rs
@@ -221,9 +221,10 @@ pub fn handle_interaction<T, R: TrezorMessage>(resp: TrezorResponse<'_, T, R>) -
TrezorResponse::Failure(_) => resp.ok(), // assering ok() returns the failure error
TrezorResponse::ButtonRequest(req) => handle_interaction(req.ack()?),
TrezorResponse::PinMatrixRequest(_) => Err(Error::UnsupportedNetwork),
- TrezorResponse::PassphraseRequest(req) => handle_interaction({
- let on_device = req.on_device();
- req.ack(!on_device)?
+ TrezorResponse::PassphraseRequest(req) => handle_interaction(if req.on_device() {
+ req.ack(true)?
+ } else {
+ req.ack_passphrase(String::new())?
}),
}
}
Why this scored 34/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.