Enforce MSG_SIGNING_MAX_LENGTH on microSD message signing
What changed, and why it matters
This commit fixes a missing safety limit in the Passport hardware wallet's microSD message-signing feature. Previously, a user could accidentally or maliciously be asked to sign an extremely large file from the microSD card, which could strain memory, cause crashes, or be used in a denial-of-service-style attack. The change restores a maximum file-size check that existed in older code but was lost when two code paths were merged. Health-check files are exempt because they already have their own built-in size limits.
Apply the patch. After applying, verify that MSG_SIGNING_MAX_LENGTH is documented and consistent with available RAM and signing UX limits, and consider adding a regression test that attempts to sign a file larger than the cap.
Security signals we found
Restores a previously enforced size cap that was removed during code consolidation
Prevents oversized message files from being loaded for signing from removable media
Limits memory pressure and potential crash/DoS surface during message signing
Gates the check on normal_signing to avoid breaking health-check protocol behavior
Evidence from the diff
The patch adds a file-size check inside HealthCheckMicrosdFlow.parse_message() before ReadFileFlow reads the file. When normal_signing is true, it opens the microSD card slot, calls os.stat(self.file_path)[6] to obtain the file size, and compares it against MSG_SIGNING_MAX_LENGTH. If the file exceeds the limit, it shows an ErrorPage and aborts. Health-check protocol files bypass this check because normal_signing is false in that mode. The change is purely additive and restores a cap that SignTextFileFlow previously enforced before consolidation in PR #636.
Changed components
ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.pymicroSD message-signing flowHealthCheckMicrosdFlow.parse_message()Inspect captured patch +23 / −0
diff --git a/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py b/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py
index 0f4683c..4de06c8 100644
--- a/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py
+++ b/ports/stm32/boards/Passport/modules/flows/health_check_microsd_flow.py
@@ -53,6 +53,29 @@ class HealthCheckMicrosdFlow(Flow):
async def parse_message(self):
from flows import ReadFileFlow
+ # Cap file size for general message signing. Health-check protocol
+ # files have implicit length constraints and are exempted.
+ if self.normal_signing:
+ import os
+ from files import CardSlot, CardMissingError
+ from pages import ErrorPage
+ from public_constants import MSG_SIGNING_MAX_LENGTH
+
+ try:
+ with CardSlot() as card:
+ size = os.stat(self.file_path)[6]
+ except CardMissingError:
+ await ErrorPage('microSD card removed.').show()
+ self.set_result(False)
+ return
+
+ if size > MSG_SIGNING_MAX_LENGTH:
+ await ErrorPage(
+ 'Message file is too long. Max length is {} bytes.'.format(MSG_SIGNING_MAX_LENGTH)
+ ).show()
+ self.set_result(False)
+ return
+
data = await ReadFileFlow(self.file_path, binary=False).run()
if not data:
Why this scored 63/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.