v0.0.2b
Pre-releaseNew Changes / Updates
Fixed a security vulnerability where cross-origin iframes could hijack top-level page USB permissions.
Previously, install() was configured with script.setRunsOnSubFrames(True), executing the polyfill across all iframes. However, WebUSBBridge._current_origin() relies on QWebEnginePage.url() to determine the origin. Since this always returns the top-level frame's URL, PySide6's public API provides no way to distinguish which specific subframe a request came from via QWebChannel.As a result, untrusted cross-origin iframes (such as ads or third-party embeds) could invoke navigator.usb.requestDevice() or getDevices(), and the request would be treated as originating from the top-level page itself. This allowed malicious iframes to spoof the origin and access any USB device previously authorized by the top-level page, completely breaking the origin isolation model.Since there is currently no reliable way to pinpoint the exact origin per frame, we have taken the safer approach and changed the setting to setRunsOnSubFrames(False) (which prevents navigator.usb from being defined inside iframes). While a real Chrome environment supports WebUSB inside cross-origin iframes with proper isolation, we decided to prioritize security over full functionality since we cannot properly validate it.We also found that install() had zero test coverage. We have newly created tests/test_install.py (utilizing real QWebEngineScript and QWebChannel). We confirmed that reverting this fix causes the newly added tests to fail.
Other 3 fixes discovered (after re-verifying Chrome's usb_device.cc):open() (JS) lacked idempotency, causing Python-side handle leaks when called twice.selectAlternateInterface() completely lacked claim requirement checks.
When a configuration was unselected, claimInterface/releaseInterface incorrectly displayed "Protected Class" as the reason.
Regression tests have been added for all of the above, and we verified they fail if the fixes are reverted.
Current Status & Disclaimer
We are actively looking into a way to properly identify subframe origins.
For now, we are keeping setRunsOnSubFrames(False) for security reasons, but we are working hard to restore setRunsOnSubFrames(True) as soon as a safe method is found.Due to these underlying issues, we cannot guarantee full functionality at this moment.
If you require stable iframe support, please wait for the upcoming version.