What changed, and why it matters
This update makes Trezor's Cardano message-signing feature refuse to sign 28-byte payloads that look like cryptographic hashes. The goal is to prevent users from accidentally signing a hash of an unknown message, which could let an attacker trick them into authorizing something they did not read. The change is a simple heuristic: if the payload is exactly 28 bytes and is not made of ordinary printable text, the device now rejects it with an error.
Review the heuristic for false positives: legitimate 28-byte binary messages that are not hashes will also be rejected. Consider whether the device should support explicit hash signing with a distinct user flow in the future, and document the limitation clearly for Cardano users and integrators.
Security signals we found
New input-validation guard added to a signing path
Heuristic rejection of hash-length payloads to prevent signing blind hashes
Test fixture added for the new failure mode
Evidence from the diff
The commit adds a guard in core/src/apps/cardano/sign_message.py. Before confirming a message payload, the code now checks whether payload length is 28 bytes and whether is_printable_ascii(payload) is false. If both are true, it raises ProcessError(“The payload is interpreted as a hash and cannot be signed”). The rationale in the comment is that 28 bytes equals the output length of Blake2b-224, a common Cardano hash size, and a genuine hash is extremely unlikely to be entirely printable ASCII. A new test fixture is added for a 28-byte non-ASCII payload, and UI test fixtures are updated.
Changed components
core/src/apps/cardano/sign_message.pycommon/tests/fixtures/cardano/sign_message.failed.jsontests/ui_tests/fixtures.jsonInspect captured patch +21 / −1
diff --git a/common/tests/fixtures/cardano/sign_message.failed.json b/common/tests/fixtures/cardano/sign_message.failed.json
index 871c660b..de635e97 100644
--- a/common/tests/fixtures/cardano/sign_message.failed.json
+++ b/common/tests/fixtures/cardano/sign_message.failed.json
@@ -19,6 +19,19 @@
"result": {
"error_message": "Must specify network_id and protocol_magic if using address_parameters"
}
+ },
+ {
+ "description": "Reject probable hash 28-byte non-ASCII payload",
+ "parameters": {
+ "signing_path": "m/1852'/1815'/4'/0/0",
+ "network_id": 1,
+ "protocol_magic": 764824073,
+ "payload": "ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00ff00",
+ "prefer_hex_display": true
+ },
+ "result": {
+ "error_message": "The payload is interpreted as a hash and cannot be signed"
+ }
}
]
}
diff --git a/core/src/apps/cardano/sign_message.py b/core/src/apps/cardano/sign_message.py
index e2882b8b..7965dd78 100644
--- a/core/src/apps/cardano/sign_message.py
+++ b/core/src/apps/cardano/sign_message.py
@@ -6,7 +6,7 @@ from trezor.wire.context import call as ctx_call
from apps.cardano.helpers.credential import Credential
from apps.cardano.helpers.paths import SCHEMA_MINT, SCHEMA_PUBKEY
-from apps.cardano.helpers.utils import derive_public_key
+from apps.cardano.helpers.utils import derive_public_key, is_printable_ascii
from apps.common import cbor
from . import addresses, seed
@@ -104,6 +104,12 @@ async def _get_confirmed_payload(size: int, prefer_hex_display: bool) -> bytes:
else b""
)
+ if size == 28 and not is_printable_ascii(payload):
+ # We do not support hashed signing yet, this is a heuristic to reject them.
+ # The length of a Blake2b224 hash is 28 bytes (224 bits).
+ # The chance of a valid hash composed of only printable ASCII is very low.
+ raise ProcessError("The payload is interpreted as a hash and cannot be signed")
+
await layout.confirm_message_payload(
payload_size=size,
payload_first_chunk=payload,
diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json
index 45d24a4c..3d6b7f4c 100644
--- a/tests/ui_tests/fixtures.json
+++ b/tests/ui_tests/fixtures.json
@@ -4787,6 +4787,7 @@
"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message[sign_short_non-ascii_payload_with_a-1f337ea4": "ac01ee961a5524fcbba7a327b417816e0e6e6ceb4fe8489e5078b547ab3b831c",
"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message_failed[missing_network_id_and_proto-21ec11cf": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message_failed[payload_too_long]": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
+"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message_failed[reject_probable_hash_28-byte-bc23f9cd": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
"T2T1_en_cardano-test_sign_message.py::test_cardano_sign_message_failed[unhashed_payload_too_long]": "8b1ccc0dbd6e6e3d02a896650ab90dd332ba4edbbcc4095e0fbb6a96e5256f75",
"T2T1_en_cardano-test_sign_tx.py::test_cardano_sign_tx[byron_to_shelley_transfer]": "2ebaaf8458ac58fe0a9237238299dae01927bce1a29b5695510d039034134602",
"T2T1_en_cardano-test_sign_tx.py::test_cardano_sign_tx[mainnet_transaction_with_change0]": "7a20525b47412bf3835dd4fc5374166342dba4492a35d40761291d9c8089a617",
Why this scored 36/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.