fix(python/thp): correctly handle maximum allowable THP message size
What changed, and why it matters
This commit fixes a bug in Trezor's Python library for handling large USB-style messages (THP protocol). Previously, if a message payload was too large, the code could silently wrap around a 16-bit length field, producing an incorrect packet size. The patch now catches that overflow and raises a clear error instead. It also removes an unused constant that capped payload length at 60,000 bytes. The fix is defensive and improves error handling, but it is in the host-side Python library, not the device firmware itself.
Treat as a low-severity hardening fix. Review whether any callers of packet_length() or THP message construction paths need additional input validation before this point, and confirm that downstream callers handle TrezorException gracefully. No urgent device-firmware response is indicated.
Security signals we found
integer overflow / truncation protection in length field encoding
explicit exception replacing silent struct.error propagation
host-side Python library only; no firmware/device code modified
removal of stale MAX_PAYLOAD_LEN constant
Evidence from the diff
In python/src/trezorlib/thp/message.py, packet_length() now wraps struct.pack(‘>H’, len(data) + CHECKSUM_LENGTH) in a try/except for struct.error. If the encoded length exceeds the u16 maximum, it raises TrezorException(‘Encoded message is too long’). In thp_io.py, the unused MAX_PAYLOAD_LEN = 60000 constant is removed. The change prevents a length-field overflow when constructing THP packets and replaces it with an explicit exception. No device-side code is changed.
Changed components
python/src/trezorlib/thp/message.pypython/src/trezorlib/thp/thp_io.pyInspect captured patch +5 / −2
diff --git a/python/src/trezorlib/thp/message.py b/python/src/trezorlib/thp/message.py
index f3b7c44a..f838a842 100644
--- a/python/src/trezorlib/thp/message.py
+++ b/python/src/trezorlib/thp/message.py
@@ -41,7 +41,11 @@ def packet_header(ctrl_byte: int, cid: int) -> bytes:
def packet_length(data: bytes) -> bytes:
- return struct.pack(">H", len(data) + CHECKSUM_LENGTH)
+ try:
+ return struct.pack(">H", len(data) + CHECKSUM_LENGTH)
+ except struct.error:
+ # indicates u16 overflow
+ raise exceptions.TrezorException("Encoded message is too long")
def _crc32(data: bytes) -> bytes:
diff --git a/python/src/trezorlib/thp/thp_io.py b/python/src/trezorlib/thp/thp_io.py
index c620d1bb..1d98b58d 100644
--- a/python/src/trezorlib/thp/thp_io.py
+++ b/python/src/trezorlib/thp/thp_io.py
@@ -28,7 +28,6 @@ from .message import FORMAT_STR_CONT, FORMAT_STR_INIT, ChecksumError, Message
INIT_HEADER_LENGTH = 5
CONT_HEADER_LENGTH = 3
-MAX_PAYLOAD_LEN = 60000
MESSAGE_TYPE_LENGTH = 2
CONTINUATION_PACKET = 0x80
Why this scored 29/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.