{"id":"CVE-2026-76894","aliases":["GHSA-vqff-r82h-9crc"],"title":"ckan-mcp-server: DataStore Table UI resource does not validate postMessage origin (in) and posts to targetOrigin \"*\" (out)","summary":"ckan-mcp-server: DataStore Table UI resource does not validate postMessage origin (in) and posts to targetOrigin \"*\" (out)","severity":"low","cvss":3.1,"cwe":["CWE-345","CWE-940"],"vendor":"aborruso","product":"@aborruso/ckan-mcp-server","ecosystem":"npm","affected":["@aborruso/ckan-mcp-server < 0.4.112"],"patched":["@aborruso/ckan-mcp-server 0.4.112"],"published":"2026-10-16","updated":"2026-10-16","sourceUpdated":"2026-10-16T19:24:46Z","source":"GHSA","sourceUrl":"https://github.com/advisories/GHSA-vqff-r82h-9crc","references":[{"url":"https://github.com/ondata/ckan-mcp-server/security/advisories/GHSA-vqff-r82h-9crc"},{"url":"https://github.com/advisories/GHSA-vqff-r82h-9crc"}],"tags":["ghsa","npm"],"ingestedAt":"2026-10-16T19:46:24.283Z","slug":"CVE-2026-76894","body":"## Overview\n\n## Summary\n\nThe MCP Apps UI resource (an interactive DataStore table rendered in the host's webview/iframe) communicates with its parent via `postMessage`. Its inbound `message` listener performs no `event.origin` validation, and its outbound messages are sent with target origin `'*'`. Any window/frame able to reach the document can inject data into the table and interfere with the MCP UI handshake, and the UI's own JSON-RPC messages are broadcast without an origin restriction.\n\n## Affected code\n\n`src/resources/datastore-table-ui.ts` (inline HTML):\n\n```js\nwindow.addEventListener('message', function (event) {\n  var msg = event.data;                    // no check of event.origin\n  if (!msg || typeof msg !== 'object') return;\n  if (msg.id !== undefined && _pending[msg.id]) { ... resolve/reject pending MCP request ... }\n  ...\n  if (data && (data.fields || data.records)) initTable(data);   // renders attacker-supplied data\n});\n\n// outbound:\nwindow.parent.postMessage({ jsonrpc: '2.0', id: id, method: method, params: params || {} }, '*');\nmcpNot: window.parent.postMessage({ jsonrpc:'2.0', method:method, params:params||{} }, '*');\n```\n\nThere is no allowlist of accepted origins for inbound messages and no fixed target origin for outbound messages.\n\n## Impact\n\n- **Content spoofing.** A frame that can `postMessage` to the UI can supply\n  arbitrary `fields`/`records`, causing the table to render fabricated rows and\n  links (e.g. a phishing `__link_url`) that appear to come from the queried\n  portal. (Values are HTML-escaped, so this is display spoofing, not script\n  injection — no XSS.)\n- **Handshake/UX interference.** Because inbound messages matching a pending `id`\n  resolve/reject the UI's MCP requests, an attacker frame can spoof responses to\n  the `ui/initialize` handshake or otherwise disrupt the panel.\n- **Outbound leakage.** Posting to `'*'` means the UI's JSON-RPC messages are\n  delivered to whatever the parent origin is; if the resource is ever embedded by\n  a context other than the trusted host, those messages leak to it.\n\nExploitability depends on the host embedding model (in a correct MCP Apps host the\nparent is the trusted host, which limits who can message the frame), so this is a\nhardening / defense-in-depth issue rather than a directly remotely-triggerable\none — hence Low.\n\n## Proof of concept\n\n- `poc/verify-no-origin-check.mjs` — static confirmation that the listener has no\n  origin check and outbound uses `'*'`:\n\n  ```\n  [x] validates event.origin             : NO\n  [x] outgoing postMessage targetOrigin  : '*' (any)\n  RESULT: VULNERABLE\n  ```\n\n- `poc/parent-spoof-poc.html` — a page that embeds the UI and injects fabricated\n  rows cross-origin with no handshake; the UI renders them.\n\n## Remediation\n\n- Validate `event.origin` against the expected host origin on every inbound\n  message; drop messages from other origins.\n- Send outbound `postMessage` with an explicit target origin (the host origin\n  established at initialize time) instead of `'*'`.\n- Optionally, bind to a nonce/channel established during `ui/initialize` so only\n  the negotiated host can drive the panel.\n\n## Affected packages\n\n- `@aborruso/ckan-mcp-server < 0.4.112`\n\n## Remediation\n\nUpgrade to a patched release:\n\n- `@aborruso/ckan-mcp-server 0.4.112`","depth":"sunlit","depthScore":17,"depthScoreParts":{"impact":17.1,"likelihood":0,"exploitation":0,"ransomware":0},"changes":[]}