fix(python): explicitly derive root fingerprint in get_root_fingerprint()
What changed, and why it matters
This is a small code-quality fix in the Trezor Python library. The function that reads the hardware wallet's unique root fingerprint now fetches it directly from the device instead of relying on a side effect of the unlock routine. The change itself is defensive and corrects an indirect dependency, but it does not appear to patch an active exploit or vulnerability in the device firmware.
Treat as a normal maintenance fix. Update the Python `trezorlib` package to include this commit if you rely on `get_root_fingerprint()` or session fingerprint caching. No urgent security response is indicated by the diff alone.
Security signals we found
Host-side library correctness fix
Removes reliance on side-effect behavior for cryptographic identity value
Adds explicit public-key fetch and bounds-checked 4-byte fingerprint derivation
No evidence of memory corruption, authentication bypass, or cryptographic weakness in the diff
Evidence from the diff
The commit modifies Session.get_root_fingerprint() in python/src/trezorlib/client.py. Previously it called self.ensure_unlocked(), which as a side effect populated self._root_fingerprint. The new code explicitly calls GET_ROOT_FINGERPRINT_MESSAGE and derives the fingerprint from the returned PublicKey.node.fingerprint. This removes a hidden dependency on ensure_unlocked() behavior and avoids an assertion failure if the unlock path no longer sets the cached fingerprint. It is a robustness/correctness fix in the host-side Python client, not a firmware-level security patch.
Changed components
python/src/trezorlib/client.pySession.get_root_fingerprint()Trezor Python client libraryInspect captured patch +4 / −2
diff --git a/python/src/trezorlib/client.py b/python/src/trezorlib/client.py
index eb85da0f..1e2f0108 100644
--- a/python/src/trezorlib/client.py
+++ b/python/src/trezorlib/client.py
@@ -97,8 +97,10 @@ class Session(t.Generic[ClientType, SessionIdType]):
@enter_context
def get_root_fingerprint(self) -> bytes:
if self._root_fingerprint is None:
- self.ensure_unlocked()
- assert self._root_fingerprint is not None
+ pubkey = self.call(GET_ROOT_FINGERPRINT_MESSAGE, expect=messages.PublicKey)
+ # can't use resp.root_fingerprint because it's not available on <1.9.4 & <2.3.5
+ assert pubkey.node.fingerprint is not None
+ self._root_fingerprint = pubkey.node.fingerprint.to_bytes(4, "big")
return self._root_fingerprint
def call(
Why this scored 26/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.