Skip to content

Conversation

@ochafik
Copy link
Collaborator

@ochafik ochafik commented Jan 7, 2026

Summary

Fixes a security issue where the default PostMessageTransport constructor was not passing the expected origin parameter, potentially allowing messages from unexpected origins.

Problem

When App.connect() is called without arguments, it creates a default PostMessageTransport(window.parent) but was missing the origin validation parameter. This could allow message spoofing from other iframes or windows.

Fix

Pass the correct origin parameter to ensure messages are validated against the expected sandbox proxy origin.

Test plan

  • Run basic-host and verify app communication works
  • Verify messages from unexpected origins are rejected

🤖 Generated with Claude Code

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 7, 2026

Open in StackBlitz

npm i https://pkg.pr.new/modelcontextprotocol/ext-apps/@modelcontextprotocol/ext-apps@207

commit: 1cc0e16

@ochafik ochafik changed the title fix: Validate postMessage origin matches sandbox proxy fix: Add missing origin parameter to PostMessageTransport default constructor Jan 7, 2026
@ochafik ochafik changed the title fix: Add missing origin parameter to PostMessageTransport default constructor fix: Add missing origin parameter to PostMessageTransport default constructor, verify origins in example sandbox proxy Jan 7, 2026
@ochafik ochafik marked this pull request as ready for review January 7, 2026 14:02
App.connect() now passes window.parent as both eventTarget and eventSource,
enabling source validation by default. This ensures apps only accept
messages from their parent window, preventing potential cross-app
message spoofing attacks.

Previously, the default transport only specified the target but not the
source for validation, meaning apps would accept messages from ANY window.
The sandbox proxy now validates that messages from the parent window
come from the expected host origin (derived from document.referrer).
This prevents malicious pages from sending spoofed messages to the sandbox.

Changes:
- Extract EXPECTED_HOST_ORIGIN from document.referrer
- Validate event.origin against expected origin for parent messages
- Use specific origin instead of '*' when sending to parent
- Reject and log messages from unexpected origins

This addresses the TODO comment that was previously in the code.
@ochafik ochafik force-pushed the ochafik/fix-postmessage-security branch from 5165379 to e43afcd Compare January 7, 2026 14:09
@ochafik ochafik requested a review from antonpk1 January 7, 2026 14:11
Use Promise.allSettled instead of Promise.all when connecting to
servers, so that a single server failure doesn't crash the entire UI.
Failed connections are logged as warnings but the UI continues with
the servers that connected successfully.

Also fixes video-resource-server missing server-utils.ts.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
@ochafik ochafik force-pushed the ochafik/fix-postmessage-security branch from e43afcd to 1cc0e16 Compare January 7, 2026 14:15
@ochafik ochafik merged commit c7ef5f0 into main Jan 7, 2026
19 checks passed
ochafik added a commit that referenced this pull request Jan 7, 2026
Adds tests for the attack vector where a malicious app tries to inject
messages into another app via:
  window.parent.parent.frames[i].frames[0].postMessage(fakeResponse, "*")

The protection (added in PR #207) is that PostMessageTransport validates
event.source matches the expected source (window.parent for apps), so
messages from other apps are rejected.

Tests added:
1. "app rejects messages from sources other than its parent"
   - Simulates injection attempt from page context
   - Verifies app remains functional after attack attempt

2. "PostMessageTransport is configured with source validation"
   - Verifies valid parent->app communication still works
   - Confirms source validation doesn't break legitimate messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
ochafik added a commit that referenced this pull request Jan 7, 2026
Adds tests for the attack vector where a malicious app tries to inject
messages into another app via:
  window.parent.parent.frames[i].frames[0].postMessage(fakeResponse, "*")

The protection (added in PR #207) is that PostMessageTransport validates
event.source matches the expected source (window.parent for apps), so
messages from other apps are rejected.

Tests added:
1. "app rejects messages from sources other than its parent"
   - Simulates injection attempt from page context
   - Verifies app remains functional after attack attempt

2. "PostMessageTransport is configured with source validation"
   - Verifies valid parent->app communication still works
   - Confirms source validation doesn't break legitimate messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
ochafik added a commit that referenced this pull request Jan 9, 2026
Merge latest changes from main including:
- Vue, Svelte, Preact, and Solid basic server examples (#141)
- safeAreaInsets support (#202)
- E2E test fixes (#206)
- npm publishing for examples (#184)
- ui.resourceUri optional (#210)
- Method names as consts (#192)
- toolInfo.id optional (#216)
- PostMessageTransport security fixes (#207, #208)
- Server-utils.ts refactoring
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants