{"id":"PYSEC-2026-2695","summary":"Open WebUI: Cross-origin postMessage confirmation bypass via action:submit","details":"### Summary\n\nThe chat message listener allows non-same-origin `input:prompt` and `action:submit` messages, so an external site can set prompt text and trigger `submitPrompt()` in an authenticated victim session. I validated this with a cross-origin attacker page that auto-posted messages and caused unauthorized `POST /api/v1/chats/new` and `POST /api/chat/completions` requests containing attacker-controlled prompts. This enables cross-site forced actions and model/tool execution under victim privileges without consent.\n\n### Details\n\nThe chat page's window message listener in `src/lib/components/chat/Chat.svelte` processes message types including `input:prompt` and `action:submit` without adequately enforcing same-origin restrictions. Based on code around lines ~597-616, input text is set directly from `event.data.text`; `action:submit` proceeds to `submitPrompt()` on the current prompt. The logic does not apply a strict origin allowlist and permits non-same-origin control of the chat input and submission flow, leading to cross-origin command execution in the victim's authenticated UI context. As a result, backend API calls (e.g., `POST /api/v1/chats/new`, `POST /api/chat/completions`) are sent under victim credentials.\n\nNormally, via the `input:prompt:submit` postMessage type, this results in a \"Confirm Prompt from Embed\" confirmation dialog:\n\nhttps://github.com/open-webui/open-webui/blob/9bd84258d09eefe7bf975878fb0e31a5dadfe0f8/src/lib/components/chat/Chat.svelte#L604-L622\n\nHowever, combining the two other types, it is possible to achieve the same effect without this confirmation:\n\nhttps://github.com/open-webui/open-webui/blob/9bd84258d09eefe7bf975878fb0e31a5dadfe0f8/src/lib/components/chat/Chat.svelte#L584-L602\n\n### PoC\n\n1. Set up a local Open WebUI instance and log in to it, making sure a model is configured\n2. Host the following HTML anywhere and visit it (optionally change http://127.0.0.1:14000 to your instance Base URL):\n\n```html\n\u003ch1\u003eClick anywhere\u003c/h1\u003e\n\u003cscript\u003e\n  function sleep(ms) {\n    return new Promise(r =\u003e setTimeout(r, ms));\n  }\n  \n  onclick = async () =\u003e {\n    w = window.open('http://127.0.0.1:14000');\n    await sleep(2000);\n    w.postMessage({ type: 'input:prompt', text: \"INJECTED PROMPT\" }, '*');\n    await sleep(500);\n    w.postMessage({ type: 'action:submit' }, '*');\n  }\n\u003c/script\u003e\n```\n\n3. Click anywhere on the page, then notice without further interaction the \"INJECTED PROMPT\" is executed on the Open WebUI instance\n\n\u003cimg width=\"874\" height=\"264\" alt=\"image\" src=\"https://github.com/user-attachments/assets/244d9015-0dbf-47e0-a30e-1c2fbbde5e58\" /\u003e\n\n### Impact\n\nConditions required: The victim must be authenticated to Open WebUI in the browser (token cookie present).\n\nThis issue enables cross-site forced actions under the victim's identity. An attacker can silently inject prompts and trigger model/tool execution (e.g., code interpreter, web search, retrieval, terminal/tool servers) as the victim without confirmation.\n\n### Original Agent Report\n\n\u003cimg width=\"400\" alt=\"app aikido dev_ai-pentests_projects_116389_assessments_019d67d4-81c8-7dd2-bb9e-0a4a774b2c78_issues_sidebarIssue=20439940 (4)\" src=\"https://github.com/user-attachments/assets/7b6521ed-d08b-446d-a918-103523d08a1e\" /\u003e","aliases":["CVE-2026-54007","GHSA-3vv5-8xxp-4f55"],"modified":"2026-07-13T16:31:52.046790598Z","published":"2026-07-13T15:46:19.013253Z","references":[{"type":"WEB","url":"https://github.com/open-webui/open-webui/security/advisories/GHSA-3vv5-8xxp-4f55"},{"type":"PACKAGE","url":"https://github.com/open-webui/open-webui"},{"type":"PACKAGE","url":"https://pypi.org/project/open-webui"},{"type":"ADVISORY","url":"https://github.com/advisories/GHSA-3vv5-8xxp-4f55"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-54007"}],"affected":[{"package":{"name":"open-webui","ecosystem":"PyPI","purl":"pkg:pypi/open-webui"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"0.9.6"}]}],"versions":["0.1.124","0.1.125","0.2.0","0.2.1","0.2.2","0.2.3","0.2.4","0.2.5","0.3.0","0.3.1","0.3.10","0.3.12","0.3.13","0.3.14","0.3.15","0.3.16","0.3.17","0.3.17.dev2","0.3.17.dev3","0.3.17.dev4","0.3.17.dev5","0.3.18","0.3.19","0.3.2","0.3.20","0.3.21","0.3.22","0.3.23","0.3.24","0.3.25","0.3.26","0.3.27","0.3.27.dev1","0.3.27.dev2","0.3.27.dev3","0.3.28","0.3.29","0.3.3","0.3.30","0.3.30.dev1","0.3.30.dev2","0.3.31","0.3.31.dev1","0.3.32","0.3.33","0.3.33.dev1","0.3.34","0.3.35","0.3.4","0.3.5","0.3.6","0.3.7","0.3.8","0.3.9","0.4.0","0.4.0.dev1","0.4.0.dev2","0.4.1","0.4.2","0.4.3","0.4.4","0.4.5","0.4.6","0.4.6.dev1","0.4.7","0.4.8","0.5.0","0.5.0.dev1","0.5.0.dev2","0.5.1","0.5.10","0.5.11","0.5.12","0.5.13","0.5.14","0.5.15","0.5.16","0.5.17","0.5.18","0.5.19","0.5.2","0.5.20","0.5.3","0.5.3.dev1","0.5.4","0.5.5","0.5.6","0.5.7","0.5.8","0.5.9","0.6.0","0.6.1","0.6.10","0.6.11","0.6.12","0.6.13","0.6.14","0.6.15","0.6.16","0.6.18","0.6.19","0.6.2","0.6.20","0.6.21","0.6.22","0.6.23","0.6.24","0.6.25","0.6.26","0.6.26.dev1","0.6.27","0.6.28","0.6.29","0.6.3","0.6.30","0.6.31","0.6.32","0.6.33","0.6.34","0.6.35","0.6.36","0.6.37","0.6.38","0.6.39","0.6.4","0.6.40","0.6.41","0.6.42","0.6.43","0.6.5","0.6.6","0.6.6.dev1","0.6.7","0.6.8","0.6.9","0.7.0","0.7.1","0.7.2","0.8.0","0.8.1","0.8.10","0.8.11","0.8.12","0.8.2","0.8.3","0.8.4","0.8.5","0.8.6","0.8.7","0.8.8","0.8.9","0.9.0","0.9.1","0.9.2","0.9.3","0.9.4","0.9.5"],"database_specific":{"source":"https://github.com/pypa/advisory-database/blob/main/vulns/open-webui/PYSEC-2026-2695.yaml"}}],"schema_version":"1.7.5","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N"}]}