jade_ota.py: port the hw target defaulting logic from update_jade_fw.py
What changed, and why it matters
This commit fixes a bug in the Jade hardware wallet's firmware update helper script. Previously, when a user ran a firmware download without explicitly saying which device model they had, the tool always assumed an old 'Jade 1.0' device. On newer devices this could cause the update to fail with an 'invalid firmware' error. The fix makes the tool look at the connected device and pick the correct firmware variant automatically. It is a reliability/usability fix rather than a remote exploit, but loading the wrong firmware onto a security device is a safety-critical mistake.
Treat as a low-severity hardening/reliability fix. Review whether any other OTA scripts or documentation still hard-code 'jade' as a default, and ensure the BOARD_TYPE/JADE_FEATURES mapping stays in sync with new hardware revisions. No urgent security patch is required, but the fix should be included in the next release.
Security signals we found
Wrong firmware variant selection for a hardware security device
Failure mode changed from silent wrong default to explicit error on unsupported hardware
Fix ports existing logic from a sibling script (update_jade_fw.py)
Commit message frames issue as preventing 'invalid firmware' error
Evidence from the diff
In jade_ota.py, the OTA helper used to default args.hwtarget to the literal string ‘jade’ (prod Jade 1.0) whenever the user did not supply –hw-target. The patch moves the defaulting logic into ota() so it can inspect the connected Jade’s info dictionary: BOARD_TYPE is mapped to ‘jade’, ‘jade1.1’, or ‘jade2.0’, and JADE_FEATURES is mapped to a normal or ‘dev’ build suffix. If the board/features combination is unrecognized, the script now errors out instead of silently choosing firmware. This mirrors logic already present in update_jade_fw.py.
Changed components
jade_ota.pyJade firmware OTA/download flowInspect captured patch +19 / −6
diff --git a/jade_ota.py b/jade_ota.py
index 251ed08..4722fcf 100755
--- a/jade_ota.py
+++ b/jade_ota.py
@@ -286,6 +286,25 @@ def get_firmware(args):
# Fetches the firmware to upload and uploads it, either by pushing a test
# mnemonic or through normal pinserver authentication.
def ota(args, jade, info, extended_replies):
+ downloading = args.downloadfw or args.downloadgdk
+ if downloading and not args.release:
+ logger.info(f'Assuming a latest stable fw download. Use --release to override')
+ args.release = 'stable' # default to latest/stable
+
+ if downloading and not args.hwtarget:
+ # Default HW target from the device we are going to update
+ board_type = info.get('BOARD_TYPE')
+ features = info.get('JADE_FEATURES')
+ hw_target = {'JADE': 'jade',
+ 'JADE_V1.1': 'jade1.1',
+ 'JADE_V2': 'jade2.0'}.get(board_type if board_type else 'JADE')
+ build_type = {'SB': '', 'DEV': 'dev'}.get(features)
+ if hw_target is None or build_type is None:
+ logger.error(f'Unsupported hardware: {board_type} / {features}')
+ sys.exit(1)
+ args.hwtarget = hw_target + build_type
+ logger.info(f'Assuming a {args.hwtarget} hardware target. Use --hw-target to override')
+
# Fetch the firmware to upload
fwlength, patchlen, fwhash, fwcompressed = get_firmware(args)
@@ -475,16 +494,10 @@ if __name__ == '__main__':
if args.release and not downloading:
logger.info('Ignoring --release release type since we are not downloading fw')
args.release = None
- elif downloading and not args.release:
- logger.info(f'Assuming a latest stable fw download. Use --release to override')
- args.release = 'stable' # default to latest/stable
if args.hwtarget and not downloading:
logger.info('Ignoring --hw-target hardware target since we are not downloading fw')
args.hwtarget = None
- elif downloading and not args.hwtarget:
- logger.info(f'Assuming a jade v1.0 hardware target. Use --hw-target to override')
- args.hwtarget = 'jade' # default to prod jade 1.0
# Create target dir if not present
if args.writecompressed and not os.path.isdir(COMP_FW_DIR):
Why this scored 31/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.