CVE-2026-87014: Open WebUI Admin Demoted Through SSO Role Vulnerability

MODERATE
Advisory Identifier: GHSA-wjwr-xfp9-r66p
CVSS 6.5
CWE-613 CWE-863
Published
Advisory Summary

CVE-2026-87014 is a MODERATE (CVSS 6.5) admin demoted through sso role vulnerability (CWE-613: Insufficient Session Expiration) affecting Open WebUI libraries in the PyPI ecosystem. The issue involves admin demoted through sso role sync keeps read and write access to all users' notes. Remediation is available by upgrading affected packages to version 0.11.1.

CVE-2026-87014 at a Glance

CVE Identifier CVE-2026-87014
GHSA Identifier GHSA-wjwr-xfp9-r66p
Severity MODERATE
CVSS v3.1 Base Score 6.5
CWE Classification CWE-613: Insufficient Session Expiration
Affected Product Open WebUI
Package Ecosystem PyPI
Published Date
Last Updated

Security Impact

CVSS: 6.5

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required High (PR:H)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality High (C:H)
Integrity High (I:H)
Availability None (A:N)

How to Fix CVE-2026-87014

To remediate this vulnerability, upgrade all affected Open WebUI dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

open-webui fixed: 0.11.1
pip install open-webui>=0.11.1
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

pip show open-webui

How to Check if You Are Affected

To determine whether your Python environment is affected by CVE-2026-87014, inspect your installed packages using pip:

pip show open-webui

Analyze the terminal output to locate any version of Open WebUI in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.11.1), your application is affected.

Note: The pip show open-webui command checks currently installed packages in your active Python environment.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-613: Insufficient Session Expiration, where according to wasc, "insufficient session expiration is when a web site permits an attacker to reuse old session credentials or session ids for authorization.". In Open WebUI, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

## Summary A user who is demoted from admin by an identity provider keeps admin-level read and write access to every user's notes, over any Socket.IO connection that was already open when the demotion happened. Open WebUI caches the user's role on the socket at connection time, and the two SSO role-sync paths, the reverse-proxy trusted role header and OAuth role mapping, changed the role in the database without tearing that cached session down. Only the admin user-management endpoints invalidated sessions, so a demotion driven by the identity provider left the old privileges live on the socket. ## Preconditions A role-sync SSO mode has to be enabled. Either trusted-header authentication with `WEBUI_AUTH_TRUSTED_ROLE_HEADER` set, which is unset by default, or OAuth with role mapping enabled, which is off by default. Deployments that change roles only through the admin panel are not affected, because that path already invalidated the user's sockets. The account has to be an admin at the moment it opens a Socket.IO connection, has to keep that connection open across the demotion, and has to be demoted through the SSO path rather than through the admin panel. Signing out, reloading the page, or any network interruption ends the exposure, because the reconnect reads a fresh role from the database. ## Impact Until the socket closes, the demoted account can open and edit any user's note through the collaborative-notes socket handlers, which grant admins access to every note. That is read and write access to other users' private notes, held by someone the operator has already removed from the admin role. The rest of the product is not affected. Every HTTP endpoint reads the role fresh from the database on each request, so the demoted account has no admin access to the REST API, no user management, no settings and no model or connection configuration. The exposure ends the moment the connection drops, and the account controls that only by keeping the browser tab open. The realistic case is off-boarding or a least-privilege downgrade performed in the identity provider, which is a normal administrative action rather than a misconfiguration. ## Fix Fixed in 0.11.1 by commit `ce3c175e260709f359d7e6cbb3132f0572098b95`. Role changes and user deletions now publish an internal event, and a session handler tears down that user's Socket.IO connections whenever the event fires, so every path that can change a role invalidates cached sessions instead of only the admin endpoints. Upgrading is sufficient, no configuration change is needed. ## Root cause Affected components: - `backend/open_webui/routers/auths.py`, the trusted-header role sync in the sign-in handler. - `backend/open_webui/utils/oauth.py`, the OAuth role sync run on login. - `backend/open_webui/socket/main.py`, which caches the user record on the socket and authorizes the collaborative-notes handlers against that cached copy. Session invalidation on role change was added as an explicit call, made at the call sites that changed a role rather than inside the role-change itself. The admin user-management endpoints made that call, the two SSO sync paths did not, and nothing else refreshed the role cached on an open socket. The socket keep-alive rewrites the cached record to reset the idle timer and preserves the stale role while doing so, so a connection that stays active is never reaped. Because the notes handlers grant full access to any note when the cached role reads admin, the gap turned into read and write access over all notes for as long as the connection lived. ## Proof of concept Deploy Open WebUI with trusted-header authentication and `WEBUI_AUTH_TRUSTED_ROLE_HEADER` set, or with OAuth role mapping enabled. Sign in as an admin and leave the browser open on a page holding a Socket.IO connection. Demote the account through the identity provider, meaning the next sign-in carries the role header set to `user`, or the account's group is changed at the OAuth provider. The database role is now `user`. Over the connection that is still open, join and edit another user's note by its id. Both are granted, because the role cached on that socket still reads admin. Performing the same demotion through the admin panel instead drops the connection and revokes the access, which is the behaviour the SSO paths were missing. This was established by source inspection against 0.11.0 rather than by an executed exploit. ## Credits Reported by @mtholmquist.

CVE-2026-87014 Affected Open WebUI Versions

1 component(s)
Fixed Versions:
0.11.1
Product / Package Ecosystem Affected Versions Fixed Version
open-webui
PyPI
≥ 0.9.0
< 0.11.1
0.11.1

References

Frequently Asked Questions

What is CVE-2026-87014?
CVE-2026-87014 is a security vulnerability in Open WebUI involving Admin demoted through SSO role sync keeps read and write access to all users' notes under CWE-613: Insufficient Session Expiration.
Which Open WebUI versions are affected?
Affected versions include releases prior to 0.11.1 across affected packages: open-webui.
What version fixes CVE-2026-87014?
Upgrading to 0.11.1 (or the latest patched release for your respective branch) resolves the vulnerability.
Is open-webui affected?
Yes, open-webui is affected in releases prior to 0.11.1. Upgrade your dependency to 0.11.1 or later.
What is the CVSS score of CVE-2026-87014?
CVE-2026-87014 has a CVSS v3.1 base score of 6.5 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N.
What CWE is associated with CVE-2026-87014?
CVE-2026-87014 is classified under CWE-613: Insufficient Session Expiration (According to WASC, "Insufficient Session Expiration is when a web site permits an attacker to reuse old session credentials or session IDs for authorization.").
How can I check PyPI dependencies for CVE-2026-87014?
Run the dependency tree command: 'pip show open-webui'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-wjwr-xfp9-r66p",
  "modified" : "2026-09-10T22:41:34Z",
  "published" : "2026-09-10T22:41:34Z",
  "aliases" : [ "CVE-2026-87014" ],
  "summary" : "Open WebUI: Admin demoted through SSO role sync keeps read and write access to all users' notes",
  "details" : "## Summary\n\nA user who is demoted from admin by an identity provider keeps admin-level read and write access to every user's notes, over any Socket.IO connection that was already open when the demotion happened. Open WebUI caches the user's role on the socket at connection time, and the two SSO role-sync paths, the reverse-proxy trusted role header and OAuth role mapping, changed the role in the database without tearing that cached session down. Only the admin user-management endpoints invalidated sessions, so a demotion driven by the identity provider left the old privileges live on the socket.\n\n## Preconditions\n\nA role-sync SSO mode has to be enabled. Either trusted-header authentication with `WEBUI_AUTH_TRUSTED_ROLE_HEADER` set, which is unset by default, or OAuth with role mapping enabled, which is off by default. Deployments that change roles only through the admin panel are not affected, because that path already invalidated the user's sockets.\n\nThe account has to be an admin at the moment it opens a Socket.IO connection, has to keep that connection open across the demotion, and has to be demoted through the SSO path rather than through the admin panel. Signing out, reloading the page, or any network interruption ends the exposure, because the reconnect reads a fresh role from the database.\n\n## Impact\n\nUntil the socket closes, the demoted account can open and edit any user's note through the collaborative-notes socket handlers, which grant admins access to every note. That is read and write access to other users' private notes, held by someone the operator has already removed from the admin role.\n\nThe rest of the product is not affected. Every HTTP endpoint reads the role fresh from the database on each request, so the demoted account has no admin access to the REST API, no user management, no settings and no model or connection configuration. The exposure ends the moment the connection drops, and the account controls that only by keeping the browser tab open.\n\nThe realistic case is off-boarding or a least-privilege downgrade performed in the identity provider, which is a normal administrative action rather than a misconfiguration.\n\n## Fix\n\nFixed in 0.11.1 by commit `ce3c175e260709f359d7e6cbb3132f0572098b95`. Role changes and user deletions now publish an internal event, and a session handler tears down that user's Socket.IO connections whenever the event fires, so every path that can change a role invalidates cached sessions instead of only the admin endpoints. Upgrading is sufficient, no configuration change is needed.\n\n## Root cause\n\nAffected components:\n\n- `backend/open_webui/routers/auths.py`, the trusted-header role sync in the sign-in handler.\n- `backend/open_webui/utils/oauth.py`, the OAuth role sync run on login.\n- `backend/open_webui/socket/main.py`, which caches the user record on the socket and authorizes the collaborative-notes handlers against that cached copy.\n\nSession invalidation on role change was added as an explicit call, made at the call sites that changed a role rather than inside the role-change itself. The admin user-management endpoints made that call, the two SSO sync paths did not, and nothing else refreshed the role cached on an open socket. The socket keep-alive rewrites the cached record to reset the idle timer and preserves the stale role while doing so, so a connection that stays active is never reaped. Because the notes handlers grant full access to any note when the cached role reads admin, the gap turned into read and write access over all notes for as long as the connection lived.\n\n## Proof of concept\n\nDeploy Open WebUI with trusted-header authentication and `WEBUI_AUTH_TRUSTED_ROLE_HEADER` set, or with OAuth role mapping enabled. Sign in as an admin and leave the browser open on a page holding a Socket.IO connection. Demote the account through the identity provider, meaning the next sign-in carries the role header set to `user`, or the account's group is changed at the OAuth provider. The database role is now `user`.\n\nOver the connection that is still open, join and edit another user's note by its id. Both are granted, because the role cached on that socket still reads admin. Performing the same demotion through the admin panel instead drops the connection and revokes the access, which is the behaviour the SSO paths were missing.\n\nThis was established by source inspection against 0.11.0 rather than by an executed exploit.\n\n## Credits\n\nReported by @mtholmquist.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "PyPI",
      "name" : "open-webui"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0.9.0"
      }, {
        "fixed" : "0.11.1"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/security/advisories/GHSA-wjwr-xfp9-r66p"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-87014"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/commit/ce3c175e260709f359d7e6cbb3132f0572098b95"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/open-webui/open-webui"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/open-webui/open-webui/releases/tag/v0.11.1"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-613", "CWE-863" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-09-10T22:41:34Z",
    "nvd_published_at" : "2026-09-09T21:17:06Z"
  }
}