fix(core): don't reuse `TASK_CLOSED` exception object
What changed, and why it matters
This change fixes a subtle bug in the Trezor device's internal task scheduler. Previously, the same exception object was reused every time a background task was closed. Reusing the same exception object can cause unexpected behavior if code catches and re-raises it, or if the exception object is modified. The fix creates a fresh exception object each time, which is safer and more predictable. There is no direct evidence in the commit that this is exploitable as a security vulnerability.
Treat as a low-risk hardening fix. Review issue #5472 for context. No urgent security response is indicated by the commit alone, but the fix should be included in the next firmware release as part of routine maintenance.
Security signals we found
Defensive fix for exception-object reuse in task scheduler
Reference to public issue #5472 suggests prior discussion of the behavior
No changelog entry, consistent with internal cleanup or minor fix
No explicit security framing in commit title or message
Evidence from the diff
In core/src/trezor/loop.py, the global singleton TASK_CLOSED = TaskClosed() was removed. The spawn syscall now instantiates a new TaskClosed() each time it coerces a GeneratorExit. Reusing a single exception instance across coroutine/task boundaries can lead to mutated exception state, incorrect traceback chaining, or surprising behavior if callers attach state to the exception. The patch is defensive and aligns with Python best practices for exception objects, but the diff alone does not demonstrate a concrete exploit or security impact.
Changed components
core/src/trezor/loop.pyspawn syscallTaskClosed exception handlingInspect captured patch +1 / −4
diff --git a/core/src/trezor/loop.py b/core/src/trezor/loop.py
index b2422fdff..ae4d6843b 100644
--- a/core/src/trezor/loop.py
+++ b/core/src/trezor/loop.py
@@ -37,9 +37,6 @@ class TaskClosed(Exception):
pass
-TASK_CLOSED = TaskClosed()
-
-
def schedule(
task: Task,
value: Any = None,
@@ -510,7 +507,7 @@ class spawn(Syscall):
self.finished = True
if isinstance(value, GeneratorExit):
# coerce GeneratorExit to a catchable TaskClosed
- self.return_value = TASK_CLOSED
+ self.return_value = TaskClosed()
else:
self.return_value = value
Why this scored 46/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.