feat: replace Ledger iframe bridge with direct WebHID transport#39537
feat: replace Ledger iframe bridge with direct WebHID transport#39537
Conversation
|
CLA Signature Action: All authors have signed the CLA. You may need to manually re-run the blocking PR check if it doesn't pass in a few minutes. |
17d276e to
d50ef66
Compare
|
All alerts resolved. Learn more about Socket for GitHub. This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
@metamaskbot update-policies |
# Conflicts: # package.json
Restores clear signing with NFT/ERC20/externalPlugins support, which shows human-readable info on the Ledger device screen. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
app/offscreen/ledger.ts
Outdated
| const version = response | ||
| .subarray(offset, offset + versionLength) | ||
| .toString('ascii'); | ||
| return { appName, version }; |
There was a problem hiding this comment.
Missing bounds checking in APDU response parsing
Low Severity
The getAppNameAndVersion handler parses the Ledger APDU response without validating the response length. If the device returns a shorter-than-expected response, response[offset] could be undefined, causing nameLength to be undefined. This would make subarray(offset, offset + undefined) behave unexpectedly (producing empty strings) rather than throwing a clear error. Adding a minimum length check before parsing would make failures more diagnosable.
Builds ready [4173451]
UI Startup Metrics (1446 ± 112 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|
Builds ready [fd29dbe]
UI Startup Metrics (1406 ± 114 ms)
📊 Page Load Benchmark ResultsCurrent Commit: 📄 Localhost MetaMask Test DappSamples: 100 Summary
📈 Detailed Results
Bundle size diffs [🚨 Warning! Bundle size has increased!]
|


Description
The current Ledger integration uses a cross-origin iframe from
metamask.github.io/ledger-iframe-bridge. This architecture has issues because cross-origin iframes cannot reliably inherit device permissions from the parent extension, and offscreen documents cannot provide user gestures forrequestDevice().This PR replaces the iframe bridge with direct WebHID usage via
@ledgerhq/hw-transport-webhidin the offscreen document. The UI already requests device permission viarequestDevice()in click handlers. The offscreen document can then access those permitted devices usinggetDevices()andTransportWebHID.openConnected()without requiring a gesture.Changelog
CHANGELOG entry: Fixed Ledger connectivity issues by replacing the iframe bridge with direct WebHID transport
Related issues
Fixes:
Manual testing steps
Screenshots/Recordings
Before
After
Pre-merge author checklist
Pre-merge reviewer checklist
Note
High Risk
Touches Ledger signing and device-transport code paths and changes the underlying connectivity mechanism from an iframe to direct WebHID, which can affect hardware-wallet availability, permission handling, and transaction/message signing reliability.
Overview
Removes the cross-origin
ledger-iframe-bridgeiframe flow and implements direct Ledger communication inapp/offscreen/ledger.tsusing@ledgerhq/hw-transport-webhid+@ledgerhq/hw-app-eth, including connect/disconnect detection vianavigator.hid, per-action transport lifecycle management, and action handling forgetPublicKey, clear-signedsignTransaction,signPersonalMessage, EIP-712signTypedData, and app name/version retrieval.Adds a comprehensive unit test suite for the new offscreen handler and updates the offscreen bridge/error propagation to serialize and rehydrate transport status errors. Updates build tooling/LavaMoat policies, Jest config coverage/matching, dependency versions, and patches
@ledgerhq/hw-transport-webhidto fix itshid-framingimport path; removes now-unneeded e2e mocking of the iframe bridge.Written by Cursor Bugbot for commit fd29dbe. This will update automatically on new commits. Configure here.