feat(clear_signing): add threshold message support
What changed, and why it matters
This commit adds a small feature to Trezor's Ethereum 'clear signing' code that lets a data format specify a custom message to show when a token amount exceeds a configured threshold. Previously the device always displayed the word 'unlimited'. There is no obvious security bug in the change itself; it is a user-interface wording feature. The commit does not fix a vulnerability.
No immediate action required. As a defensive review, verify that threshold_message values from external ERC-7730 definitions are length-limited and sanitized before display, to avoid unexpected UI truncation or rendering issues. Confirm the TODO about native_currency_address being dead code is tracked separately.
Security signals we found
UI display string now configurable via external ERC-7730 metadata
No sanitization of threshold_message is shown in the diff
Default fallback to existing translated string preserves prior behavior
Evidence from the diff
The patch extends TokenAmountFormatter with an optional threshold_message parameter. When amount > threshold, the formatter now returns AboveThreshold(self.threshold_message or TR.words__unlimited) instead of hard-coding the translation string for ‘unlimited’. A decode_path() helper is updated to pass info.threshold_message into the formatter constructor. The change is additive and preserves the previous default behavior when no custom message is supplied. No input validation changes are visible in the diff.
Changed components
core/src/apps/ethereum/clear_signing.pyTokenAmountFormatter classdecode_path() ERC-7730 path decoderInspect captured patch +15 / −2
### core/src/apps/ethereum/clear_signing.py
@@ -335,11 +335,13 @@ def __init__(
const_token_address: bytes | None = None,
native_currency_address: list[bytes] | None = None,
threshold: int | None = None,
+ threshold_message: str | None = None,
) -> None:
self.token_path = token_path
self.const_token_address = const_token_address
self.native_currency_address = native_currency_address
self.threshold = threshold
+ self.threshold_message = threshold_message
async def format(
self,
@@ -369,10 +371,15 @@ async def format(
else:
raise InvalidFormatDefinition
+ # TODO: Dead code. We don't pull this externally but we should.
if self.native_currency_address is not None:
if token_address in self.native_currency_address:
if self.threshold is not None and amount > self.threshold:
- return AboveThreshold(TR.words__unlimited), None, None
+ return (
+ AboveThreshold(self.threshold_message or TR.words__unlimited),
+ None,
+ None,
+ )
else:
return (
format_ethereum_amount(amount, None, defs.network),
@@ -392,7 +399,11 @@ async def format(
token = received_definitions.get_token(token_address)
if self.threshold is not None and amount > self.threshold:
- return AboveThreshold(TR.words__unlimited), token, token_address
+ return (
+ AboveThreshold(self.threshold_message or TR.words__unlimited),
+ token,
+ token_address,
+ )
else:
return (
format_ethereum_amount(amount, token, defs.network),
@@ -864,6 +875,8 @@ def decode_path(p: EthereumERC7730Path) -> Path:
)
if info.threshold is not None:
formatter_params["threshold"] = int.from_bytes(info.threshold, "big")
+ if info.threshold_message is not None:
+ formatter_params["threshold_message"] = info.threshold_message
formatter = TokenAmountFormatter(**formatter_params)
elif fmt_type == FT.FORMATTER_UNIT:
formatter_params = {}Why this scored 18/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.