fix(cardano): stop trimming long messages
What changed, and why it matters
This commit fixes a display issue in Trezor's Cardano message signing feature. Previously, very long messages were visually trimmed on the device screen, so the user could not see the full content before approving a signature. The patch removes the trimming limit and adds a test case for a long payload. The risk is that a user might unknowingly sign a message whose full content they did not review, but the signature itself is still produced over the complete message (not a truncated one).
Treat as a low-severity UI hardening fix. Verify that the full payload is now paginated or scrollable on the device screen so users can actually review it, and confirm that the signing logic already hashes/signs the complete payload rather than the displayed portion. No urgent patch action is required beyond normal firmware update cadence.
Security signals we found
UI truncation of user-reviewable data before cryptographic approval
Removal of an arbitrary display-size cap for message payloads
Addition of regression test for long Cardano message payloads
Evidence from the diff
In core/src/apps/cardano/layout.py, confirm_message_payload() previously passed MAX_CHUNK_SIZE as max_displayed_size to _get_data_chunk_props(), causing long payloads to be truncated on the device display. The patch removes the import of MAX_CHUNK_SIZE and passes max_displayed_size=None, which the helper now interprets as ‘do not truncate’. A new test fixture with a long payload is added to common/tests/fixtures/cardano/sign_message.json. The change is purely UI/display; the cryptographic signing path is not modified in this diff.
Changed components
Trezor firmware Cardano app UI/layout layerCardano sign_message test fixturesInspect captured patch +24 / −8
diff --git a/common/tests/fixtures/cardano/sign_message.json b/common/tests/fixtures/cardano/sign_message.json
index 85688c2a..2d2c6bfa 100644
--- a/common/tests/fixtures/cardano/sign_message.json
+++ b/common/tests/fixtures/cardano/sign_message.json
@@ -105,6 +105,21 @@
"address": "d9553a4de9c7ad8532abdb1d0a7f425b8007d25c9f1edcf0b5f5c3ba",
"pub_key": "67e3d14e1e0db2a6ff68832994451f63d3e92a4ee85c3681d72634ccfe889f2c"
}
+ },
+ {
+ "description": "Long payload",
+ "parameters": {
+ "signing_path": "m/1852'/1815'/4'/0/0",
+ "network_id": 1,
+ "protocol_magic": 764824073,
+ "payload": "aaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff00011100011aaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbddd1bbbdddaafffaaafff000111000111bbbdddaaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff00011100011aaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbdddaaafffaaafff000111000111bbbddd1bbbdddaafffaaafff000111000111bbbdddee",
+ "prefer_hex_display": true
+ },
+ "result": {
+ "signature": "6d1e9bf2f704413b1a99340bb88f27a4a74f00fe7ed891b814a9a0167b6482b0b92982a5eb0be513fe5e432c4a79550d615222cf9ffcf70f42f8e600bf302c0f",
+ "address": "d9553a4de9c7ad8532abdb1d0a7f425b8007d25c9f1edcf0b5f5c3ba",
+ "pub_key": "67e3d14e1e0db2a6ff68832994451f63d3e92a4ee85c3681d72634ccfe889f2c"
+ }
}
]
}
diff --git a/core/src/apps/cardano/layout.py b/core/src/apps/cardano/layout.py
index 128a8c90..164c1ea3 100644
--- a/core/src/apps/cardano/layout.py
+++ b/core/src/apps/cardano/layout.py
@@ -12,7 +12,6 @@ from trezor.strings import format_amount, format_amount_unit
from trezor.ui import layouts
from trezor.ui.layouts import confirm_metadata, confirm_properties
-from apps.cardano.helpers.chunks import MAX_CHUNK_SIZE
from apps.common.paths import address_n_to_str
from . import addresses
@@ -329,8 +328,6 @@ async def confirm_message_payload(
) -> None:
props: list[PropertyType]
- max_displayed_bytes = MAX_CHUNK_SIZE
-
if not payload:
assert payload_size == 0
props = _get_data_chunk_props(
@@ -343,7 +340,7 @@ async def confirm_message_payload(
title=TR.cardano__message_text,
first_chunk=payload,
data_size=payload_size,
- max_displayed_size=max_displayed_bytes,
+ max_displayed_size=None,
decoder=lambda chunk: chunk.decode("ascii"),
)
else:
@@ -351,7 +348,7 @@ async def confirm_message_payload(
title=TR.cardano__message_hex,
first_chunk=payload,
data_size=payload_size,
- max_displayed_size=max_displayed_bytes,
+ max_displayed_size=None,
)
await confirm_properties(
@@ -366,10 +363,14 @@ def _get_data_chunk_props(
title: str,
first_chunk: bytes,
data_size: int,
- max_displayed_size: int = _DEFAULT_MAX_DISPLAYED_CHUNK_SIZE,
+ max_displayed_size: int | None = _DEFAULT_MAX_DISPLAYED_CHUNK_SIZE,
decoder: Callable[[bytes], bytes | str] | None = None,
) -> list[PropertyType]:
- displayed_bytes = first_chunk[:max_displayed_size]
+ displayed_bytes = (
+ first_chunk[:max_displayed_size]
+ if max_displayed_size is not None
+ else first_chunk
+ )
bytes_optional_plural = "byte" if data_size == 1 else "bytes"
props: list[PropertyType] = [
(
@@ -378,7 +379,7 @@ def _get_data_chunk_props(
True,
)
]
- if data_size > max_displayed_size:
+ if max_displayed_size is not None and data_size > max_displayed_size:
props.append(("...", None, None))
return props
Why this scored 34/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.