feat(core): add notifications device wipe & unpairing
What changed, and why it matters
This commit adds informational notifications when a Trezor device is wiped or a Bluetooth pairing is removed. It does not change who can perform these actions or how they are authorized. The wipe/unpair logic itself already existed; the change only tells connected software that the event is happening. There is no obvious security vulnerability here.
No security action required. Treat as a normal feature commit. If reviewing further, verify that notify_send is non-blocking and that the 300 ms delay does not introduce any race condition or UI/UX issue, and that the notification cannot be used to bypass existing wipe/unpair authorization.
Security signals we found
New notification events NOTIFY_WIPE and NOTIFY_UNPAIR added to sys/notify.h
Notifications emitted before erase_device() in bootloader wipe workflow
Notifications emitted before BLE bond erasure in firmware wipe_device and unpair flows
300 ms utime.sleep_ms() delay inserted after notification send to allow host delivery
No changes to authentication, authorization, or cryptographic erase logic
Evidence from the diff
The patch introduces two new notification event constants, NOTIFY_WIPE and NOTIFY_UNPAIR, exposes them through the MicroPython trezorutils module, and emits them in the bootloader wipe workflow, the firmware wipe_device app, and the BLE unpair app. A 300 ms delay is added after sending the notification so the host has time to receive it before bonds are erased or the device reboots. The authorization checks and actual erase/unpair operations are unchanged.
Changed components
core/embed/projects/bootloader/workflow/wf_wipe_device.ccore/embed/sys/notify/inc/sys/notify.hcore/embed/upymod/modtrezorutils/modtrezorutils.ccore/mocks/generated/trezorutils.pyicore/src/apps/management/ble/unpair.pycore/src/apps/management/wipe_device.pycore/src/trezor/utils.pyInspect captured patch +44 / −11
diff --git a/core/embed/projects/bootloader/workflow/wf_wipe_device.c b/core/embed/projects/bootloader/workflow/wf_wipe_device.c
index 7fac10f6..4553bf45 100644
--- a/core/embed/projects/bootloader/workflow/wf_wipe_device.c
+++ b/core/embed/projects/bootloader/workflow/wf_wipe_device.c
@@ -20,6 +20,7 @@
#include <trezor_model.h>
#include <trezor_rtl.h>
+#include <sys/notify.h>
#include <util/flash_utils.h>
#ifdef USE_BLE
@@ -108,6 +109,9 @@ workflow_result_t workflow_wipe_device(protob_io_t* iface) {
return WF_CANCELLED;
}
ui_screen_wipe();
+
+ notify_send(NOTIFY_WIPE);
+
secbool wipe_result = erase_device(ui_screen_wipe_progress);
if (sectrue != wipe_result) {
diff --git a/core/embed/sys/notify/inc/sys/notify.h b/core/embed/sys/notify/inc/sys/notify.h
index d146980a..6c792a4f 100644
--- a/core/embed/sys/notify/inc/sys/notify.h
+++ b/core/embed/sys/notify/inc/sys/notify.h
@@ -48,7 +48,9 @@ typedef enum {
5, /**< Device soft-locked (e.g., after clicking power button) */
NOTIFY_SOFTUNLOCK =
6, /**< Device soft-unlocked (e.g., after successful pin entry) */
- NOTIFY_PIN_CHANGE = 7 /**< Pin changed on the device */
+ NOTIFY_PIN_CHANGE = 7, /**< Pin changed on the device */
+ NOTIFY_WIPE = 8, /**< Factory reset (wipe) invoked */
+ NOTIFY_UNPAIR = 9 /**< BLE bonding for current connection deleted */
// Additional notification types can be added here as needed
} notification_event_t;
diff --git a/core/embed/upymod/modtrezorutils/modtrezorutils.c b/core/embed/upymod/modtrezorutils/modtrezorutils.c
index 5900c097..626ace8d 100644
--- a/core/embed/upymod/modtrezorutils/modtrezorutils.c
+++ b/core/embed/upymod/modtrezorutils/modtrezorutils.c
@@ -690,11 +690,15 @@ STATIC mp_obj_tuple_t mod_trezorutils_version_obj = {
/// NOTIFY_SETTING_CHANGE: int
/// """Notification event: change of settings"""
/// NOTIFY_SOFTLOCK: int
-/// """Notification event: device soft-locked (e.g., after pressing power
-/// button)""" NOTIFY_SOFTUNLOCK: int
-/// """Notification event: device soft-unlocked (e.g., after successful PIN
-/// entry)""" NOTIFY_PIN_CHANGE: int
+/// """Notification event: device soft-locked"""
+/// NOTIFY_SOFTUNLOCK: int
+/// """Notification event: device soft-unlocked"""
+/// NOTIFY_PIN_CHANGE: int
/// """Notification event: PIN changed on the device"""
+/// NOTIFY_WIPE: int
+/// """Notification event: factory reset (wipe) invoked"""
+/// NOTIFY_UNPAIR: int
+/// """Notification event: BLE bonding for current connection deleted"""
///
/// if __debug__:
/// DISABLE_ANIMATION: bool
@@ -729,6 +733,8 @@ STATIC const mp_rom_map_elem_t mp_module_trezorutils_globals_table[] = {
{MP_ROM_QSTR(MP_QSTR_NOTIFY_SOFTLOCK), MP_ROM_INT(NOTIFY_SOFTLOCK)},
{MP_ROM_QSTR(MP_QSTR_NOTIFY_SOFTUNLOCK), MP_ROM_INT(NOTIFY_SOFTUNLOCK)},
{MP_ROM_QSTR(MP_QSTR_NOTIFY_PIN_CHANGE), MP_ROM_INT(NOTIFY_PIN_CHANGE)},
+ {MP_ROM_QSTR(MP_QSTR_NOTIFY_WIPE), MP_ROM_INT(NOTIFY_WIPE)},
+ {MP_ROM_QSTR(MP_QSTR_NOTIFY_UNPAIR), MP_ROM_INT(NOTIFY_UNPAIR)},
#ifdef USE_NRF
{MP_ROM_QSTR(MP_QSTR_nrf_get_version),
MP_ROM_PTR(&mod_trezorutils_nrf_get_version_obj)},
diff --git a/core/mocks/generated/trezorutils.pyi b/core/mocks/generated/trezorutils.pyi
index 00d7ac84..54c25615 100644
--- a/core/mocks/generated/trezorutils.pyi
+++ b/core/mocks/generated/trezorutils.pyi
@@ -251,11 +251,15 @@ NOTIFY_DISCONNECT: int
NOTIFY_SETTING_CHANGE: int
"""Notification event: change of settings"""
NOTIFY_SOFTLOCK: int
-"""Notification event: device soft-locked (e.g., after pressing power
-button)""" NOTIFY_SOFTUNLOCK: int
-"""Notification event: device soft-unlocked (e.g., after successful PIN
-entry)""" NOTIFY_PIN_CHANGE: int
+"""Notification event: device soft-locked"""
+NOTIFY_SOFTUNLOCK: int
+"""Notification event: device soft-unlocked"""
+NOTIFY_PIN_CHANGE: int
"""Notification event: PIN changed on the device"""
+NOTIFY_WIPE: int
+"""Notification event: factory reset (wipe) invoked"""
+NOTIFY_UNPAIR: int
+"""Notification event: BLE bonding for current connection deleted"""
if __debug__:
DISABLE_ANIMATION: bool
diff --git a/core/src/apps/management/ble/unpair.py b/core/src/apps/management/ble/unpair.py
index 7371acbc..473896f5 100644
--- a/core/src/apps/management/ble/unpair.py
+++ b/core/src/apps/management/ble/unpair.py
@@ -1,7 +1,8 @@
+import utime
from typing import TYPE_CHECKING
import trezorble as ble
-from trezor import TR
+from trezor import TR, utils
if TYPE_CHECKING:
from trezor.messages import BleUnpair
@@ -38,11 +39,19 @@ async def unpair(msg: BleUnpair) -> None:
if msg.all:
from apps.thp.credential_manager import invalidate_cred_auth_key
+ if ble.is_connected():
+ utils.notify_send(utils.NOTIFY_UNPAIR)
+ utime.sleep_ms(300)
+
# THP credentials should be invalidated when "Forget all" is handled.
# Otherwise, the device will not ask for THP confirmation after reconnecting.
invalidate_cred_auth_key()
ble.erase_bonds()
else:
+ if msg.addr == ble.connected_addr():
+ utils.notify_send(utils.NOTIFY_UNPAIR)
+ utime.sleep_ms(300)
+
ble.unpair(msg.addr)
if msg.all:
diff --git a/core/src/apps/management/wipe_device.py b/core/src/apps/management/wipe_device.py
index 4f964c49..5f765247 100644
--- a/core/src/apps/management/wipe_device.py
+++ b/core/src/apps/management/wipe_device.py
@@ -1,3 +1,4 @@
+import utime
from typing import TYPE_CHECKING
from trezor import utils
@@ -58,9 +59,15 @@ async def wipe_device(msg: WipeDevice) -> None:
# reload settings
reload_settings_from_storage()
+ # notify host about the wipe
+ utils.notify_send(utils.NOTIFY_WIPE)
+
if utils.USE_BLE:
from trezorble import erase_bonds
+ # wait for the notification to be sent
+ utime.sleep_ms(300)
+
# raise an exception if bonds erasing fails
erase_bonds()
diff --git a/core/src/trezor/utils.py b/core/src/trezor/utils.py
index c953599b..8be3a1b8 100644
--- a/core/src/trezor/utils.py
+++ b/core/src/trezor/utils.py
@@ -17,6 +17,8 @@ from trezorutils import ( # noqa: F401
NOTIFY_SOFTLOCK,
NOTIFY_SOFTUNLOCK,
NOTIFY_UNLOCK,
+ NOTIFY_UNPAIR,
+ NOTIFY_WIPE,
SCM_REVISION,
UI_LAYOUT,
USE_BACKLIGHT,
@@ -52,7 +54,6 @@ from trezorutils import ( # noqa: F401
if USE_NRF:
from trezorutils import nrf_get_version # noqa: F401
-
from typing import TYPE_CHECKING
if __debug__:
Why this scored 20/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.