chore(core): raise exception for invalid ThpCreateNewSession messages [no changelog]
What changed, and why it matters
This commit tightens how the Trezor hardware wallet handles passphrase-protected sessions. Previously, a host could supply a passphrase in a message even when the device was configured to require the passphrase only on the device. Now the firmware raises an error in that case, preventing the host from silently overriding the 'always on device' setting. The change also adds a debug-only warning when a session is created with a passphrase while passphrase protection is disabled on the device.
Review the THP (Trezor Host Protocol) session creation flow to confirm no other paths bypass the on-device passphrase requirement, and consider adding regression tests for the PASSPHRASE_ALWAYS_ON_DEVICE + host-supplied passphrase case. No urgent action is required unless this change is part of a larger security fix release.
Security signals we found
Input validation added for ThpCreateNewSession messages
Host-supplied passphrase now rejected when PASSPHRASE_ALWAYS_ON_DEVICE is enabled
Behavior change from silent acceptance to explicit DataError
Debug logging added for inconsistent passphrase configuration
Evidence from the diff
In core/src/apps/common/passphrase.py, get_passphrase() now reads storage_device.get_passphrase_always_on_device() once and uses it consistently. If that setting is True and the incoming ThpCreateNewSession message contains a non-None passphrase, the function raises DataError. Previously the code returned an empty string when passphrase protection was disabled, and only checked always_on_device inside the else branch, which could allow a host-supplied passphrase to be used when the device intended passphrase entry to be on-device only. A debug log warning was also added for the disabled-but-passphrase-supplied case.
Changed components
core/src/apps/common/passphrase.pyTrezor Core firmwareThpCreateNewSession message handlingPassphrase entry flowInspect captured patch +19 / −3
diff --git a/core/src/apps/common/passphrase.py b/core/src/apps/common/passphrase.py
index 3478115e..a20d5bc8 100644
--- a/core/src/apps/common/passphrase.py
+++ b/core/src/apps/common/passphrase.py
@@ -10,16 +10,32 @@ _MAX_PASSPHRASE_LEN = const(50)
if TYPE_CHECKING:
from trezor.messages import ThpCreateNewSession
+if __debug__:
+ from trezor import log
+
def is_enabled() -> bool:
return storage_device.is_passphrase_enabled()
async def get_passphrase(msg: ThpCreateNewSession) -> str:
- if not is_enabled():
- return ""
+ passphrase_always_on_device = storage_device.get_passphrase_always_on_device()
+
+ # Device setting "disabled passphrase protection" is ignored
+ if __debug__:
+ if not is_enabled() and msg.passphrase:
+ log.warning(
+ __name__,
+ "Creating new session with passphrase, ignoring device settings.",
+ )
+
+ # When always_on_device is True, messages with passphrase raise a DataError
+ if passphrase_always_on_device and msg.passphrase is not None:
+ raise DataError(
+ "Providing passphrase in message is not allowed when PASSPHRASE_ALWAYS_ON_DEVICE is True."
+ )
- if msg.on_device or storage_device.get_passphrase_always_on_device():
+ if msg.on_device or passphrase_always_on_device:
passphrase = await _get_on_device()
else:
passphrase = msg.passphrase or ""
Why this scored 37/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.