fix(core/eckhart): wrong return flow message
What changed, and why it matters
This commit fixes a UI flow bug in the Trezor hardware wallet (Eckhart/T3W1 layout). When a user was setting up a new PIN, opened the menu, chose 'Cancel PIN setup', and then confirmed the cancellation, the device accidentally reported 'success/confirmed' instead of 'cancelled'. This could mislead connected software into thinking the user had approved PIN setup when they actually aborted it.
Treat as a low-to-moderate UI/state-machine bug. Verify the fix in device tests and regression-test the PIN setup/cancellation flow on T3W1. No emergency response is indicated, but the fix should be included in the next firmware release.
Security signals we found
Incorrect UI flow return message could cause host software to misinterpret user cancellation as confirmation
PIN setup cancellation state machine bug in Rust UI flow controller
Test updated to exercise the real cancel path and assert cancellation is still reported
Evidence from the diff
In core/embed/rust/src/ui/layout_eckhart/flow/confirm_set_new_pin.rs, the state transition for (Self::Cancel, FlowMsg::Confirmed) was changed from returning FlowMsg::Confirmed to returning FlowMsg::Cancelled. The Cancel screen is reached from the menu’s ‘Cancel PIN setup’ option; confirming on that screen should abort the flow, but it was previously emitting the wrong return message. The device test was updated to navigate the actual menu path (menu → ‘Cancel PIN setup’ → confirm) and still expects a Cancelled exception, and UI fixture hashes were refreshed for all languages.
Changed components
Trezor Core firmwareEckhart/T3W1 UI layoutSetNewPin flow controllerPIN change/setup flowInspect captured patch +15 / −8
diff --git a/core/embed/rust/src/ui/layout_eckhart/flow/confirm_set_new_pin.rs b/core/embed/rust/src/ui/layout_eckhart/flow/confirm_set_new_pin.rs
index 010abccd..c7ab4db3 100644
--- a/core/embed/rust/src/ui/layout_eckhart/flow/confirm_set_new_pin.rs
+++ b/core/embed/rust/src/ui/layout_eckhart/flow/confirm_set_new_pin.rs
@@ -48,7 +48,7 @@ impl FlowController for SetNewPin {
(Self::Menu, FlowMsg::Choice(0)) => Self::Cancel.goto(),
(Self::Menu, FlowMsg::Cancelled) => Self::Intro.goto(),
(Self::Cancel, FlowMsg::Cancelled) => Self::Intro.goto(),
- (Self::Cancel, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Confirmed),
+ (Self::Cancel, FlowMsg::Confirmed) => self.return_msg(FlowMsg::Cancelled),
_ => self.do_nothing(),
}
}
diff --git a/tests/device_tests/test_msg_changepin_t2.py b/tests/device_tests/test_msg_changepin_t2.py
index fb8140b4..83536d48 100644
--- a/tests/device_tests/test_msg_changepin_t2.py
+++ b/tests/device_tests/test_msg_changepin_t2.py
@@ -200,7 +200,14 @@ def test_pin_menu_cancel_setup(session: Session):
# tap to confirm
debug.click(debug.screen_buttons.tap_to_confirm())
elif session.client.layout_type is LayoutType.Eckhart:
- debug.press_no()
+ # enter context menu
+ debug.click(debug.screen_buttons.menu())
+ debug.synchronize_at("VerticalMenu")
+ # click "Cancel PIN setup"
+ debug.click(debug.screen_buttons.vertical_menu_items()[0])
+ # tap to confirm
+ debug.synchronize_at("TextScreen")
+ debug.click(debug.screen_buttons.ok())
with session.client as client, pytest.raises(Cancelled):
client.set_input_flow(cancel_pin_setup_input_flow)
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 2d91e716..13e0e33f 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -29873,7 +29873,7 @@
"T3W1_cs_test_msg_changepin_t2.py::test_change_failed": "909e6872ce758f391140357197220851f96a356a2663c1696f5a7a1b16d2c6e9",
"T3W1_cs_test_msg_changepin_t2.py::test_change_invalid_current": "e0d56cfd74e5e0c404f1339d19f843fac24610c421dc4c98d9ce815fe1e3c147",
"T3W1_cs_test_msg_changepin_t2.py::test_change_pin": "9aa180b85a2552e04ece6f907fe6cb9ed7d38e75fcbe9231efd68478db80397f",
-"T3W1_cs_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "2c5aa76d64bc0ff39d15e87d865aa4f99d6d665eece6c13d6b8f3ca5ce316bea",
+"T3W1_cs_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "2dcc9f66e78c723aa84e2991b4af5d97d291a84d583a0c9d140692ce84eec694",
"T3W1_cs_test_msg_changepin_t2.py::test_remove_pin": "c3723a609f6cdbffd3e4517a4179e8e7a6ee1663da80d74bc5470eb86efa1cee",
"T3W1_cs_test_msg_changepin_t2.py::test_set_failed": "14634b0957f8f7268fb446d18653272302dfb6cc561bd1965e91cb5dcbe604fd",
"T3W1_cs_test_msg_changepin_t2.py::test_set_pin": "4f135f2e7eaa75978c945a25a494e77224899d7f91e306c54c74156fcdc8ccef",
@@ -31323,7 +31323,7 @@
"T3W1_de_test_msg_changepin_t2.py::test_change_failed": "822d5a5d95d30fdc775f6dd429b52108471f8c7efcc4d99f151ae229e5061285",
"T3W1_de_test_msg_changepin_t2.py::test_change_invalid_current": "25dd428c90b1e5efcc1e16bafaecc4b0bbecde41c5dbb116e789c16142f9b31b",
"T3W1_de_test_msg_changepin_t2.py::test_change_pin": "f1884ad1e97020c36f8a0161051cdc59028c84c10fd429c5062e4f628b7a2339",
-"T3W1_de_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "cbd00f3eafd5a400df3f66e7cb6febb4df9ec3dff827db2c79a77bfeee42634c",
+"T3W1_de_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "8a2d0d171f1010d201728ff108a157795f403aa0fa9f69f341e9a7d289b7fe29",
"T3W1_de_test_msg_changepin_t2.py::test_remove_pin": "ce56b5086b3eaceef01ecdd01c18c8ec52e0d7c859f485628d7d288549e100d7",
"T3W1_de_test_msg_changepin_t2.py::test_set_failed": "0fe97d15e329b31b4eef77a8178ad7d6a1a00d31ef61e81cbf0332d427ad991c",
"T3W1_de_test_msg_changepin_t2.py::test_set_pin": "183e558e53ec82848ce7d3693ab0fa956727c24529d151c6a990462bf9baf819",
@@ -32773,7 +32773,7 @@
"T3W1_en_test_msg_changepin_t2.py::test_change_failed": "514c4cd29ece849e08f1e3da98c77155b3c08789f392aa78dc9174ffd0a02715",
"T3W1_en_test_msg_changepin_t2.py::test_change_invalid_current": "524c3be65fea63c9f379fe377817164bc845691bf7c7bbbaf524daf14c574ad1",
"T3W1_en_test_msg_changepin_t2.py::test_change_pin": "284dbd89033e821bf05587f40b8b92deb361a814bf3a745b1b9957a4c28e9044",
-"T3W1_en_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "9365d802b16eb5e6c5ca4bb16440a52acf01d493314aafe9a9c78e1f8828255e",
+"T3W1_en_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "146d5cf5f074ce21ee2f4d135713e9c653e161015d3bc38be09fac0e645eb71e",
"T3W1_en_test_msg_changepin_t2.py::test_remove_pin": "a1452dfe8338eb58ad8072aeeb956bc296b3fa20f41bb293c31f4e31e4a0b822",
"T3W1_en_test_msg_changepin_t2.py::test_set_failed": "3d35bc92687ae201abfdb237311cc454cc9fd0d7f670687a5d649d476d7b6c45",
"T3W1_en_test_msg_changepin_t2.py::test_set_pin": "5b782147469b0466cc3897e770d9d234bd532133c3ed4dd5047cf94d3f9b7549",
@@ -34223,7 +34223,7 @@
"T3W1_es_test_msg_changepin_t2.py::test_change_failed": "efbe67ffbe2bc5e9388c04b90071f460f4ff0c7d6c8412d570f495ab2d83b5ad",
"T3W1_es_test_msg_changepin_t2.py::test_change_invalid_current": "5c94f18914d7ab88d9ab01bc0a6fb4525d912c1b5ddae2294881049908f5bab6",
"T3W1_es_test_msg_changepin_t2.py::test_change_pin": "bb30f2213dd1f4183e3260d2ca5d617a42f9a3793edb2596ef618067922346ca",
-"T3W1_es_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "be3030e4830b5b5d2394fbd3214276912d9edbdb1b61f616e87f80d606bc3c35",
+"T3W1_es_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "3f2c85778977fe73935a46c8771ec3974c24081f9c0f51352a8dcadd71b73fc0",
"T3W1_es_test_msg_changepin_t2.py::test_remove_pin": "79e02756ac2edfc2fcac64ac0b5a4e5ec29a0bd5bb6ca29cdb127f26f59d9dd0",
"T3W1_es_test_msg_changepin_t2.py::test_set_failed": "261a0c2100b99e3641dc89865cd308d0bd877ce11a43b7aed31b0af3c623a48b",
"T3W1_es_test_msg_changepin_t2.py::test_set_pin": "24e2c9c45afccc7b060008a0acc6ee99ac9c4299d30d8eb7f40ceca5932d47fe",
@@ -35673,7 +35673,7 @@
"T3W1_fr_test_msg_changepin_t2.py::test_change_failed": "e4b960194157927c874d38bb4abca7e7e289c0ce7e94569508a0fd23f6ba0241",
"T3W1_fr_test_msg_changepin_t2.py::test_change_invalid_current": "b90476810ac2ffa4bd59fd00154f76ac29dea407dab539ff09ba5bfbdf1a9592",
"T3W1_fr_test_msg_changepin_t2.py::test_change_pin": "ffbfa07a8bccac69a627839049f689ce389357deda8e064c3d51c82f521ec2bf",
-"T3W1_fr_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "e3191afee729c17d1f09d892c27dac481b86352c20e8bb7da050e590bda43d8d",
+"T3W1_fr_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "52df72f8a53e6f4ad58f282d0038c8a8f5081a21610ceb36105b0064bd0f05b4",
"T3W1_fr_test_msg_changepin_t2.py::test_remove_pin": "41d7a88652b8881b2f2a3e40b59b536503f28afa2442e00ef623c72dd1fdd5ad",
"T3W1_fr_test_msg_changepin_t2.py::test_set_failed": "c4754594d4f71d9fa5c27aa752f8e273afd53750eb56b7260f00d84f4388119d",
"T3W1_fr_test_msg_changepin_t2.py::test_set_pin": "dd405bb96515386e150626b2c739768c9225d23ced4a83643a1006fcbc553d06",
@@ -37123,7 +37123,7 @@
"T3W1_pt_test_msg_changepin_t2.py::test_change_failed": "9fb056b69dfb0677779a4abcd90a6321fdeab232a6c05d2d8fecb858e3f4f37b",
"T3W1_pt_test_msg_changepin_t2.py::test_change_invalid_current": "169cc6e8471f3719022fb71a5504dae5c8794656526428a84f2c3d8661c92395",
"T3W1_pt_test_msg_changepin_t2.py::test_change_pin": "42952ff6ad3483f88bcd1459402b242ff5c9e6456a91df3a4a6185a5acd0c3ec",
-"T3W1_pt_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "ca99a7c11c9d8acd2afcee7041a7151746b2c1bc70df28eb027b19ff743019d3",
+"T3W1_pt_test_msg_changepin_t2.py::test_pin_menu_cancel_setup": "05044fb35ddee15d2df78f4e0c9acbd3d1cc1bef6735a18b5c1e8807d484304a",
"T3W1_pt_test_msg_changepin_t2.py::test_remove_pin": "06c841b6e8bc14fef862f553bb5e755428f21472b80a79ba487a8d51014dc1cd",
"T3W1_pt_test_msg_changepin_t2.py::test_set_failed": "93dee74fcc64e9e6bd3fb4e2a21f83e08a0897a731fdd12db5d2566e8c462721",
"T3W1_pt_test_msg_changepin_t2.py::test_set_pin": "962e63d0309a5fed0f93d35e90e4b3fb9fa0b5365aa739b6bc64a68aa7886108",
Why this scored 35/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.