{"schema":"threatline.record/2","record":{"id":"CVE-2026-76894","aliases":["GHSA-vqff-r82h-9crc"],"summary":"ckan-mcp-server: DataStore Table UI resource does not validate postMessage origin (in) and posts to targetOrigin \"*\" (out)","details":"## 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.","categories":["Libraries & packages"],"product":"@aborruso/ckan-mcp-server","vendor":"","ecosystem":"npm","affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-vqff-r82h-9crc","source_modified_at":"2026-10-16T19:24:46Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"@aborruso/ckan-mcp-server"},"range":"< 0.4.112"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-vqff-r82h-9crc","source_modified_at":"2026-10-16T19:30:03.948336425Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"@aborruso/ckan-mcp-server","ecosystem":"npm","purl":"pkg:npm/%40aborruso/ckan-mcp-server"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"0.4.112"}]}],"versions":[]}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/advisories/GHSA-vqff-r82h-9crc","source_modified_at":"2026-10-16T19:24:46Z","fetched_at":"2026-10-23T18:42:43.628194Z","package":{"ecosystem":"npm","name":"@aborruso/ckan-mcp-server"},"version":"0.4.112"},{"source":"OSV","source_url":"https://osv.dev/vulnerability/GHSA-vqff-r82h-9crc","source_modified_at":"2026-10-16T19:30:03.948336425Z","fetched_at":"2026-10-23T18:45:31.882637Z","package":{"name":"@aborruso/ckan-mcp-server","ecosystem":"npm","purl":"pkg:npm/%40aborruso/ckan-mcp-server"},"version":"0.4.112"}],"cvss":3.1,"severity":"Low","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-16T19:23:48Z","modified_at":"2026-10-16T19:30:03.948336425Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/advisories/GHSA-vqff-r82h-9crc","fetched_at":"2026-10-23T18:42:43.628194Z","source_modified_at":"2026-10-16T19:24:46Z"},{"source":"OSV","url":"https://osv.dev/vulnerability/GHSA-vqff-r82h-9crc","fetched_at":"2026-10-23T18:45:31.882637Z","source_modified_at":"2026-10-16T19:30:03.948336425Z"}],"sources":["GitHub Advisory Database","OSV"],"references":[{"url":"https://github.com/ondata/ckan-mcp-server/security/advisories/GHSA-vqff-r82h-9crc","source":"GitHub Advisory Database"},{"url":"https://github.com/advisories/GHSA-vqff-r82h-9crc","source":"GitHub Advisory Database"}],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":"ecosystem","confidence":"heuristic","reviewed":false},"change_timestamp":"2026-10-16T19:30:03.948336425Z","content_hash":"1ee2689072f41698111e6dfec041ec03e0ee1988460e81e6b82dac01b18eae3b"}}
