fix(core): set model variant in THP DeviceProperties
What changed, and why it matters
This commit finishes a previously incomplete feature in Trezor's new wireless pairing protocol (THP). Before the fix, the device told the connecting computer/phone its model variant as 'None' (effectively blank). After the fix, it correctly reports the device's color, whether it is a Bitcoin-only edition, and its packaging type. This is mostly a correctness/functional fix, but an incorrect or missing model variant could in theory confuse host software during pairing or cause it to trust the wrong device identity. There is no direct evidence in the commit of an exploitable vulnerability.
Treat as a normal functional fix. Reviewers should confirm that model_variant values are consumed safely by host software and that no host-side logic misinterprets the new bitmask. No urgent security action is indicated by the diff alone.
Security signals we found
Previously hard-coded model_variant=None now populated with device-specific fields
Affects THP (Trezor Host Protocol) device identification during pairing
No input validation changes, no buffer/memory operations, no privilege changes
No changelog entry and no vendor security statement in commit
Evidence from the diff
In core/src/trezor/wire/thp/init.py the _get_device_properties() function replaces the hard-coded model_variant=None with a computed bitmask using utils.unit_color(), utils.unit_btconly(), and utils.unit_packaging(). The TODO ‘define model variants’ is removed. The change propagates into THP DeviceProperties used during the Trezor Host Protocol pairing/identification phase. The tests/ui_tests/fixtures.json changes are only expected UI-test hash updates for T3W1 pairing-code-entry tests across locales, reflecting the altered on-screen flow/data caused by populating model_variant. No security boundary is visibly crossed and no advisory/CVE/vendor disclosure is present.
Changed components
core/src/trezor/wire/thp/__init__.pyTHP DeviceProperties message generationT3W1 pairing code entry UI testsInspect captured patch +18 / −14
diff --git a/core/src/trezor/wire/thp/__init__.py b/core/src/trezor/wire/thp/__init__.py
index 3a8b0baa2..38c56329a 100644
--- a/core/src/trezor/wire/thp/__init__.py
+++ b/core/src/trezor/wire/thp/__init__.py
@@ -200,11 +200,15 @@ def get_enabled_pairing_methods(
def _get_device_properties(iface: WireInterface) -> ThpDeviceProperties:
- # TODO define model variants
+ model_variant = (
+ (utils.unit_color() or 0)
+ | (int(utils.unit_btconly() or False) << 8)
+ | ((utils.unit_packaging() or 0) << 16)
+ )
return ThpDeviceProperties(
pairing_methods=get_enabled_pairing_methods(iface),
internal_model=utils.INTERNAL_MODEL,
- model_variant=None,
+ model_variant=model_variant,
protocol_version_major=2,
protocol_version_minor=0,
)
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 9e65acf29..abfc29734 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -30199,8 +30199,8 @@
"T3W1_cs_thp-test_pairing.py::test_credential_request_in_encrypted_transport_phase": "447df4a910a08d586c42bded66f8d954d6f265856c4037a0bc51fd16f2613b68",
"T3W1_cs_thp-test_pairing.py::test_pairing_cancel_1": "26682c257ae82f7a94438d5543f28d9f72a780dacc34676465e83de9dc719a5d",
"T3W1_cs_thp-test_pairing.py::test_pairing_cancel_2": "98b20959693b19764fb61dc09c4cb971ba3ea9b5c8ea072dfe8ea752e5f5899e",
-"T3W1_cs_thp-test_pairing.py::test_pairing_code_entry": "7390327a85bf9177c4ab464d37f29dbc66ad61226cb44b61206ca66e68ce0cb2",
-"T3W1_cs_thp-test_pairing.py::test_pairing_code_entry_cancel": "7390327a85bf9177c4ab464d37f29dbc66ad61226cb44b61206ca66e68ce0cb2",
+"T3W1_cs_thp-test_pairing.py::test_pairing_code_entry": "982e251cd90242d85b2a2656b4dd3f731b5ebd95bb7138a2d4d8ec1e19c9fd5e",
+"T3W1_cs_thp-test_pairing.py::test_pairing_code_entry_cancel": "982e251cd90242d85b2a2656b4dd3f731b5ebd95bb7138a2d4d8ec1e19c9fd5e",
"T3W1_cs_thp-test_pairing.py::test_pairing_nfc": "b29ae9b97a580fb295fdd86c1b754ed5bb38cb011a9a79cfd281c8517ce7a4ff",
"T3W1_cs_thp-test_pairing.py::test_pairing_qr_code": "535037bfe5f1459cfdf305915835d8bf2a9a427c3f60264a8cc3ca6f306a61b1",
"T3W1_cs_webauthn-test_msg_webauthn.py::test_add_remove": "e306dd20ec722d1081d43822e2427021f853b291843cb0e670a01d2c8fb13fba",
@@ -31659,8 +31659,8 @@
"T3W1_de_thp-test_pairing.py::test_credential_request_in_encrypted_transport_phase": "f17b7adbd2e15cdbc7fc3c1b75626e7e58149940ed6ee21ab0eee453a03d958a",
"T3W1_de_thp-test_pairing.py::test_pairing_cancel_1": "a3e81c59c99554a9065c35de00cc51f7a58c3c05b972c71424c94ee56e648b49",
"T3W1_de_thp-test_pairing.py::test_pairing_cancel_2": "f2c3692d802ae2ae92085da1ebcb104de820fa3124ce7ce340bcf67116a1f842",
-"T3W1_de_thp-test_pairing.py::test_pairing_code_entry": "d1d8bfa11eebbd3ee9632e82d41c09657b472d374c1bb76bfee1f5b08bfbe83e",
-"T3W1_de_thp-test_pairing.py::test_pairing_code_entry_cancel": "d1d8bfa11eebbd3ee9632e82d41c09657b472d374c1bb76bfee1f5b08bfbe83e",
+"T3W1_de_thp-test_pairing.py::test_pairing_code_entry": "7db9aa4b62ea0a3e0ad7945a00404b770f596665e39f05f2a7f112ceabb8f523",
+"T3W1_de_thp-test_pairing.py::test_pairing_code_entry_cancel": "7db9aa4b62ea0a3e0ad7945a00404b770f596665e39f05f2a7f112ceabb8f523",
"T3W1_de_thp-test_pairing.py::test_pairing_nfc": "73b326ae8ba956abb0a5c409e15f1c39e2c6e0f5921730fecf8464767b422bbb",
"T3W1_de_thp-test_pairing.py::test_pairing_qr_code": "2bf2200d3f158d1cffae639cd632a3b651fe53af5942b65eb881cfce12817592",
"T3W1_de_webauthn-test_msg_webauthn.py::test_add_remove": "b931d0d50cbeb0067bfcd21c30a56289c5228a4e9a2db0f1a2cdd80b3354114b",
@@ -33119,8 +33119,8 @@
"T3W1_en_thp-test_pairing.py::test_credential_request_in_encrypted_transport_phase": "9ecedd8a32fa670d27f1c69bbd3cfd0f0a96a6e98b687342d9f5f14a68b28255",
"T3W1_en_thp-test_pairing.py::test_pairing_cancel_1": "ee9dd4f800b7d1d55b03897e8c3a9ac12587b5c88b62e3e164dda2f82b2d2b89",
"T3W1_en_thp-test_pairing.py::test_pairing_cancel_2": "311ee774cb007244ab02479513f34636d5b3525ded32c9c639ae402d9f4c6647",
-"T3W1_en_thp-test_pairing.py::test_pairing_code_entry": "46be1d370643d9d7aad3fc5fd48e35571cee1f407778ce609c8488e8a841df11",
-"T3W1_en_thp-test_pairing.py::test_pairing_code_entry_cancel": "46be1d370643d9d7aad3fc5fd48e35571cee1f407778ce609c8488e8a841df11",
+"T3W1_en_thp-test_pairing.py::test_pairing_code_entry": "9eebe489eeb4648c3d003afcbfe1e433f9c531e22e7c69a004ee87e5256709b6",
+"T3W1_en_thp-test_pairing.py::test_pairing_code_entry_cancel": "9eebe489eeb4648c3d003afcbfe1e433f9c531e22e7c69a004ee87e5256709b6",
"T3W1_en_thp-test_pairing.py::test_pairing_nfc": "b4bfd637d737dd5e8c4c196cdbd993dcbb845337e483041602005c3431faa452",
"T3W1_en_thp-test_pairing.py::test_pairing_qr_code": "2b19d878184abddf53159d4acb504a1e86a7c2d5fd15de433495742ba7df9cc8",
"T3W1_en_webauthn-test_msg_webauthn.py::test_add_remove": "510629c4e529258068c0cf1e25fca02bad81344c3e16dca1cba5ce63f5682bc5",
@@ -34579,8 +34579,8 @@
"T3W1_es_thp-test_pairing.py::test_credential_request_in_encrypted_transport_phase": "b3e3bd3176b15dfbfe98794cd1047ec8012465b4e6ee16425c0f650faae03ff3",
"T3W1_es_thp-test_pairing.py::test_pairing_cancel_1": "c2591097c84b15ac795d77afd9d7903ee8a75c4062c266aed2d21685b4a5df23",
"T3W1_es_thp-test_pairing.py::test_pairing_cancel_2": "5958e821d7498782bffc4278bb531602fa86673389c4be22140e38cd0e263c74",
-"T3W1_es_thp-test_pairing.py::test_pairing_code_entry": "54e149a980c5df5a5c67f5b3166513897c0b9628855aff6aa4528ba97f5bab8f",
-"T3W1_es_thp-test_pairing.py::test_pairing_code_entry_cancel": "54e149a980c5df5a5c67f5b3166513897c0b9628855aff6aa4528ba97f5bab8f",
+"T3W1_es_thp-test_pairing.py::test_pairing_code_entry": "ee1d181ec57ad3976602809663ee59676bf7c5b939e4d34c565fe026a09c47d6",
+"T3W1_es_thp-test_pairing.py::test_pairing_code_entry_cancel": "ee1d181ec57ad3976602809663ee59676bf7c5b939e4d34c565fe026a09c47d6",
"T3W1_es_thp-test_pairing.py::test_pairing_nfc": "8530de54915a9fb05ca08d0f09f28bb333488396f2c86c32ff16b5f3797e5565",
"T3W1_es_thp-test_pairing.py::test_pairing_qr_code": "991c2fedae415c4284948d276edc08daeea466ca5849934ed2784cc8884ee589",
"T3W1_es_webauthn-test_msg_webauthn.py::test_add_remove": "123756d9e78d54136d537d479821d99a8e9e98e236b8b455760b1ad769c1ab7a",
@@ -36039,8 +36039,8 @@
"T3W1_fr_thp-test_pairing.py::test_credential_request_in_encrypted_transport_phase": "4f856ed456252093228bf49937960d22062647ae0a6be1d8b5e68f1565f12dde",
"T3W1_fr_thp-test_pairing.py::test_pairing_cancel_1": "117f093c6764135753dbc7b1df400eb4d9e56996520ea4ca5864d6e5d19ff381",
"T3W1_fr_thp-test_pairing.py::test_pairing_cancel_2": "5cdac2aa6934b76fd04e8a3d9e3407411229f29915549babbfc38bc8195691dc",
-"T3W1_fr_thp-test_pairing.py::test_pairing_code_entry": "82e8893ebb3a9a09ff75aeee4c360415d17e41248ce4fabb3dbdc974089b1afa",
-"T3W1_fr_thp-test_pairing.py::test_pairing_code_entry_cancel": "82e8893ebb3a9a09ff75aeee4c360415d17e41248ce4fabb3dbdc974089b1afa",
+"T3W1_fr_thp-test_pairing.py::test_pairing_code_entry": "2b6378d2853966dc8e287f7fea00a5981852bdadbdf864eeab44d92aebc22c60",
+"T3W1_fr_thp-test_pairing.py::test_pairing_code_entry_cancel": "2b6378d2853966dc8e287f7fea00a5981852bdadbdf864eeab44d92aebc22c60",
"T3W1_fr_thp-test_pairing.py::test_pairing_nfc": "d4934773ca4fe2bf34da753b157a76d273aee47c333f6a6ba6d504aa268a75a0",
"T3W1_fr_thp-test_pairing.py::test_pairing_qr_code": "250f727140e1737e1e25e4620b4557d886c40e53f8205987dacb8904050dc474",
"T3W1_fr_webauthn-test_msg_webauthn.py::test_add_remove": "a7b20833f3d5524acf135340ab90967bbac7d0b5942d55431f3351b7eb5dfb6f",
@@ -37499,8 +37499,8 @@
"T3W1_pt_thp-test_pairing.py::test_credential_request_in_encrypted_transport_phase": "1d096a92e581f540d4a434ca92bf2b52f2e8d59f450d92a7744de89999a78e36",
"T3W1_pt_thp-test_pairing.py::test_pairing_cancel_1": "1354f82a9d51bba8655fc8fd8695c0d0327f5babd7b7e0329bdeaa86e0e44f1c",
"T3W1_pt_thp-test_pairing.py::test_pairing_cancel_2": "47ba37925299d73ea3bc6e9269d53fb3307635f480ce9a299c896828daa28191",
-"T3W1_pt_thp-test_pairing.py::test_pairing_code_entry": "86d95a11ea21f18b1e911e3903a9f649e1e8147fd7a812cf8ee70924ed25e3ed",
-"T3W1_pt_thp-test_pairing.py::test_pairing_code_entry_cancel": "86d95a11ea21f18b1e911e3903a9f649e1e8147fd7a812cf8ee70924ed25e3ed",
+"T3W1_pt_thp-test_pairing.py::test_pairing_code_entry": "1536309e2e9345cd3ddbc83f1903e1ee120b07ea01563c534dd004dd656ed9b8",
+"T3W1_pt_thp-test_pairing.py::test_pairing_code_entry_cancel": "1536309e2e9345cd3ddbc83f1903e1ee120b07ea01563c534dd004dd656ed9b8",
"T3W1_pt_thp-test_pairing.py::test_pairing_nfc": "d3109c384c4d64822fdee5a8cb9e09b913f906cdbab1650096ebcdb5a30c47ea",
"T3W1_pt_thp-test_pairing.py::test_pairing_qr_code": "637658c0c6bbf3267f67895c12aeea91280f0471133d7865e4b0d19bdd1da874",
"T3W1_pt_webauthn-test_msg_webauthn.py::test_add_remove": "29b7be125acfa0bd4f5f6c2110b9f25c53ad195ea07716bb6e2ecb8199a8b133",
Why this scored 23/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.