What changed, and why it matters
This update fixes a bug in the Trezor hardware wallet where a specific secure connection protocol (THP) would freeze while the user was entering their PIN to unlock the device. The fix keeps the protocol alive so the connected computer can still exchange basic keep-alive messages (like pings) during unlock, preventing connection timeouts or stalls.
Treat as a stability and user-experience fix with minor security relevance. Review whether any messages processed during unlock could leak state or be abused; the current implementation drops unexpected messages, which is appropriate. No immediate security response required beyond normal merge and regression testing.
Security signals we found
Fixes a denial-of-service-like stall in the THP handshake during PIN unlock
Adds concurrent message handling to prevent protocol timeout while device is soft-locked
Permits ping/pong keep-alive during unlock, improving connection stability
Includes regression test verifying responsiveness during unlock
Evidence from the diff
The commit modifies received_message_handler.py in the Trezor Core THP (Trezor Host Protocol) implementation. Previously, when a handshake requested device unlock, the code awaited workflow.spawn(unlock_device()) directly, which blocked THP message processing. The patch introduces _handle_thp_during_unlock, which concurrently reassembles and drops unexpected THP messages while allowing preemption and ping/pong handling via loop.race(unlock, handle). A test is added to verify the device remains responsive during the PIN unlock flow.
Changed components
core/src/trezor/wire/thp/received_message_handler.pytests/device_tests/thp/test_handshake.pyT3W1 device THP handshake/unlock flowInspect captured patch +27 / −2
diff --git a/core/.changelog.d/6145.fixed b/core/.changelog.d/6145.fixed
new file mode 100644
index 000000000..028029707
--- /dev/null
+++ b/core/.changelog.d/6145.fixed
@@ -0,0 +1 @@
+[T3W1] Don't stall THP handling during PIN unlock.
diff --git a/core/src/trezor/wire/thp/received_message_handler.py b/core/src/trezor/wire/thp/received_message_handler.py
index b1db41067..74b208962 100644
--- a/core/src/trezor/wire/thp/received_message_handler.py
+++ b/core/src/trezor/wire/thp/received_message_handler.py
@@ -81,6 +81,23 @@ async def handle_received_message(channel: Channel) -> bool:
return False
+async def _handle_thp_during_unlock(channel: Channel) -> None:
+ """
+ Keep handling THP messages while waiting for unlock.
+ It allows preemption and ping/pong handling if the device is soft-locked.
+ """
+ while True:
+ # may raise ChannelPreemptedException if another channel preempts this one
+ msg = await channel._get_reassembled_message()
+ if __debug__:
+ # we don't expect messages from this channel since the handshake is not over
+ channel._log(
+ "drop unexpected message",
+ utils.hexlify_if_bytes(msg),
+ logger=log.warning,
+ )
+
+
async def _handle_state_handshake(
ctx: Channel,
) -> None:
@@ -107,14 +124,16 @@ async def _handle_state_handshake(
return
if try_to_unlock:
- from trezor import workflow
+ from trezor import loop, workflow
from apps.common.lock_manager import unlock_device
# Register the unlock prompt with the workflow management system
# (in order to avoid immediately respawning the lockscreen task)
try:
- return await workflow.spawn(unlock_device())
+ unlock = workflow.spawn(unlock_device())
+ handle = _handle_thp_during_unlock(channel=ctx)
+ return await loop.race(unlock, handle)
except Exception as e:
if __debug__:
log.exception(__name__, e)
diff --git a/tests/device_tests/thp/test_handshake.py b/tests/device_tests/thp/test_handshake.py
index a5abcb10e..f659d5ce6 100644
--- a/tests/device_tests/thp/test_handshake.py
+++ b/tests/device_tests/thp/test_handshake.py
@@ -87,6 +87,11 @@ def test_unlock_pin(client: Client):
protocol._send_handshake_init_request(try_to_unlock=True)
protocol._read_ack()
debug.synchronize_at("PinKeyboard")
+
+ # the device is responsive during unlock flow
+ protocol.transport.ping()
+ protocol.sync_responses()
+
debug.input(PIN4)
protocol._read_handshake_init_response()
Why this scored 33/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.