limit BIP-322 msg length to 330 chars
What changed, and why it matters
This commit adds a 330-character limit to BIP-322 proof-of-reserve messages on the COLDCARD hardware wallet. Without the limit, an attacker could craft a very long message that might be used to mislead the user, overflow display buffers, or cause other unexpected behavior during signing. The change rejects oversized or empty messages before the user is asked to sign.
No immediate action for users; ensure firmware is updated to a version containing this commit. Developers should verify that 330 bytes is sufficient for intended use cases and that the assertion is consistently enforced across all BIP-322 entry points.
Security signals we found
Input length bound added to user-facing signed message
Assertion failure prevents processing of oversized messages
Empty message already rejected; documentation now also requires non-empty message
New unit tests cover boundary values (330 allowed, 331 rejected, empty rejected)
Evidence from the diff
The patch enforces that the decoded PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE (used for BIP-322 proof-of-reserves) is non-empty and at most 330 bytes. It adds an assertion in shared/psbt.py and updates the documentation and tests accordingly. The fix is a straightforward input-length guard on a message that is shown to the user and signed.
Changed components
shared/psbt.pydocs/proof-of-reserves-bip-322.mdtesting/test_bip322.pyInspect captured patch +41 / −1
diff --git a/docs/proof-of-reserves-bip-322.md b/docs/proof-of-reserves-bip-322.md
index 4df4ffa..4d2d66b 100644
--- a/docs/proof-of-reserves-bip-322.md
+++ b/docs/proof-of-reserves-bip-322.md
@@ -14,7 +14,8 @@ must meet all these requirements:
adds signatures to the PSBT. Finalizing and encoding the final BIP-322
signature string is the responsibility of the finalizer.
* PSBT MUST include `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE = 0x09`; the value is
- the exact message shown to the user and signed by BIP-322.
+ the exact message shown to the user and signed by BIP-322. The decoded
+ message must be non-empty and no longer than 330 characters.
* PSBT requires `PSBT_IN_BIP32_DERIVATION` for each input
* P2SH wrapped segwit addresses MUST have proper redeem script in PSBT: `PSBT_IN_REDEEM_SCRIPT`
* P2WSH segwit addresses MUST have proper witness script in PSBT: `PSBT_IN_WITNESS_SCRIPT`
diff --git a/shared/psbt.py b/shared/psbt.py
index b5c19f5..ae20e57 100644
--- a/shared/psbt.py
+++ b/shared/psbt.py
@@ -1532,6 +1532,7 @@ class psbtObject(psbtProxy):
self.por322 = bool(self.por322_msg)
if self.por322:
+ assert len(self.por322_msg) <= 330, "msg len"
if len(self.por322_msg) != len(self.por322_msg.encode()):
self.warnings.append((
"Message",
diff --git a/testing/test_bip322.py b/testing/test_bip322.py
index 33a5cc5..46392ad 100644
--- a/testing/test_bip322.py
+++ b/testing/test_bip322.py
@@ -733,4 +733,42 @@ def test_bip322_empty_message_challenge_rejected(bip32_paths, por, bip322_txn,
title, story = cap_story()
assert title == "Failure"
+
+@pytest.mark.parametrize("msg", [
+ b"A"*330, # allowed
+ b"X"*331, # too long
+ b"", # empty
+])
+def test_msg_size(msg, bip322_txn, start_sign, end_sign, cap_story, need_keypress,
+ press_select, press_cancel, bip322_verify):
+
+ psbt, msg_challenge = bip322_txn([["p2wpkh", None, None]], msg=msg)
+
+ start_sign(psbt, finalize=True)
+
+ time.sleep(.1)
+ title, story = cap_story()
+
+ if 0 < len(msg) <= 330:
+ assert title == "OK TO SIGN?"
+ assert "BIP-322 Message" in story
+ assert "sign message" in story
+
+ assert ("Message:\n%s" % msg.decode()) in story
+
+ signed = end_sign(accept=True, exit_export_loop=False)
+ bip322_verify(signed)
+ title, story = cap_story()
+ assert title == "PSBT Signed"
+ assert "Signed BIP-322 PSBT shared via USB." in story
+ press_cancel()
+
+ else:
+ assert title == "Failure"
+ if msg:
+ assert "msg len" in story
+ else:
+ assert "msg" in story
+
+
# EOF
Why this scored 38/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.