v0.0.3b
Pre-release
Pre-release
Summary of Implementation
frame_origin.py(New Module) —FrameOriginTracker- The Python side (the completely zero-trust side that does not trust JS at all) traverses the frame tree using
page.mainFrame()/QWebEngineFrame.children(). - It distributes an unguessable token to each frame via
runJavaScript(), ensuring it is delivered only to that specific frame. - Other frames cannot read this token due to the Same-Origin Policy.
- Retraversal is triggered by the
navigationRequestedsignal (discovered in0.0.3a0), with a periodic 2-second interval scan running in parallel as a safeguard.
- The Python side (the completely zero-trust side that does not trust JS at all) traverses the frame tree using
- Token Integration Across Slots
- Added a
frame_tokenparameter to all 16@Slotmethods (ranging fromlistDevicesto various transfer-related methods). - Routed the token through
_get_open_device(), a bottleneck method that almost all other methods pass through. - This fully operationalized the feature, ensuring that "a handle opened by a subframe can continuously and exclusively be used by that subframe."
- Added a
- Core Design Rule
- When wiring the tracker, origins are resolved strictly via tokens without exception, including the main frame.
- We intentionally left no loopholes like "an empty token defaults to the main frame."
- Allowing such a loophole would let an adversarial subframe impersonate the main frame simply by invoking the raw
QWebChanneldirectly with an empty token.
Pitfalls & Fixes
Verified on an actual QWebEnginePage, discovering and resolving three implementation pitfalls:
runJavaScript()Error- Passing only the code string as a single argument throws a "not enough arguments" error. A callback function is strictly required.
setHtml()URL BehaviorsetHtml(html, baseUrl=...)fails to reflect thebaseUrlinQWebEngineFrame.url(), treating it as adata:URL instead. Usingpage.load()works correctly.
QWebEngineFrameIdentity Issue- The
QWebEngineFrameobject returns a brand-new wrapper every timechildren()is called. - This makes frame identification via
id()completely unreliable. We removed the dependency on unique IDs and resolved this by issuing fresh tokens on every scan while enforcing an upper limit on the total token count.
- The
Testing
test_frame_origin.py(New, 9 test cases)- Includes 8 fast tests using mocks.
- Includes 1 integration test using a real
QWebEnginePageand cross-origin iframes.
test_bridge.pyUpdates (2 test cases added)- Added tests for token spoofing rejection and handle isolation between origins.
- Legacy Test Maintenance
- Updated existing Python/JS tests to support the new signature (updating 16 instances of the
fakeBridgemock).
- Updated existing Python/JS tests to support the new signature (updating 16 instances of the
Note: Since we cannot guarantee stable operation under all conditions yet, please wait for the next version release.