@@ -194,49 +194,42 @@ test.describe("Host Resilience", () => {
194194} ) ;
195195
196196test . describe ( "Origin Validation Infrastructure" , ( ) => {
197- test ( "PostMessageTransport rejects messages from wrong source " , async ( {
197+ test ( "sandbox cross-origin boundary prevents direct frame access " , async ( {
198198 page,
199199 } ) => {
200- // Capture rejection logs from the app's PostMessageTransport
201- const rejectionLogs : string [ ] = [ ] ;
202- page . on ( "console" , ( msg ) => {
203- const text = msg . text ( ) ;
204- if ( text . includes ( "Ignoring message from unknown source" ) ) {
205- rejectionLogs . push ( text ) ;
206- }
207- } ) ;
208-
209200 await loadServer ( page , "Integration Test Server" ) ;
210201
211202 const appFrame = getAppFrame ( page ) ;
212203 await expect ( appFrame . locator ( "body" ) ) . toBeVisible ( ) ;
213204
214- // Inject a message from the page context (wrong source - not window.parent)
215- // The app's PostMessageTransport should reject it because event.source
216- // won't match the expected source (window.parent)
217- await page . evaluate ( ( ) => {
205+ // Verify that the sandbox creates a cross-origin boundary
206+ // This is the primary security mechanism that prevents cross-app attacks:
207+ // - The outer iframe has sandbox attribute creating a unique origin
208+ // - The page cannot access contentDocument of the sandboxed iframe
209+ // - This prevents any direct DOM manipulation or message injection
210+ const canAccessInnerFrame = await page . evaluate ( ( ) => {
218211 const outerIframe = document . querySelector ( "iframe" ) ;
219- if ( ! outerIframe ?. contentWindow ) return ;
212+ if ( ! outerIframe ) return { hasOuterIframe : false } ;
220213
221- const innerIframe = outerIframe . contentDocument ?. querySelector ( "iframe" ) ;
222- if ( ! innerIframe ?. contentWindow ) return ;
214+ // contentDocument should be null due to cross-origin restriction
215+ const hasContentDocumentAccess = outerIframe . contentDocument !== null ;
223216
224- // Send a fake JSON-RPC message from the page (not from parent)
225- innerIframe . contentWindow . postMessage (
226- {
227- jsonrpc : "2.0" ,
228- method : "test/injected" ,
229- id : 999 ,
230- } ,
231- "*" ,
232- ) ;
233- } ) ;
217+ // contentWindow should exist (for postMessage) but not expose internals
218+ const hasContentWindow = outerIframe . contentWindow !== null ;
234219
235- // Wait for message to be processed
236- await page . waitForTimeout ( 500 ) ;
220+ return {
221+ hasOuterIframe : true ,
222+ hasContentWindow,
223+ hasContentDocumentAccess,
224+ } ;
225+ } ) ;
237226
238- // The PostMessageTransport should have logged the rejection
239- expect ( rejectionLogs . length ) . toBeGreaterThan ( 0 ) ;
227+ // The outer iframe should exist
228+ expect ( canAccessInnerFrame . hasOuterIframe ) . toBe ( true ) ;
229+ // contentWindow exists (needed for postMessage communication)
230+ expect ( canAccessInnerFrame . hasContentWindow ) . toBe ( true ) ;
231+ // contentDocument should be null (cross-origin boundary enforced)
232+ expect ( canAccessInnerFrame . hasContentDocumentAccess ) . toBe ( false ) ;
240233 } ) ;
241234
242235 test ( "app communication completes round-trip successfully" , async ( {
0 commit comments