The GitHub advisory database published 53 Open WebUI advisories between 24 July and 10 September 2026 (18 high, 30 medium, 5 low, no critical), out of 164 active advisories for the project. Every one was fixed in a release before it was published, and no active advisory lists 0.11.1 or later as affected, while 0.11.0 sits inside 17 vulnerable ranges and 0.10.2 inside 34. Of the 53, 30 need a setting or feature that is off by default (terminal servers, channels, OAuth token exchange, outbound fetch settings such as the Playwright loader, a non-default vector store and eight smaller ones), and 23 are reachable on a default install. Only 3 of the 53 need no account at all, so this batch is an insider and compromised-account problem. Two settings undo a fix after you upgrade: ENABLE_OAUTH_TOKEN_EXCHANGE without OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS, and ENABLE_PYODIDE_FILE_PERSISTENCE=true. The release notes for v0.11.0 through v0.11.4 (except the v0.11.3 hotfix) warn that some security fixes are withheld for a short time, and advisories trailed releases by 8 to 25 days in the last three batches. Pin v0.11.4, not the last version named in an advisory. Start by running curl against /api/version on every instance you own.
The GitHub advisory database published 53 Open WebUI vulnerabilities between 24 July and 10 September 2026: 18 high, 30 medium, 5 low. Add the older records and the project carries 164 active advisories. If you run Open WebUI as the chat front end to a private vLLM or Ollama deployment, your change board is going to ask whether you are exposed, and a severity-sorted list will not answer that question.
The setting that opens each advisory answers it. Thirty of the 53 need a feature or configuration value that ships disabled. Only three can be reached without an account. And one fact ends most triage before it starts: on 25 September 2026, no active advisory lists 0.11.1 or later as affected.
This post maps each advisory in that window to the setting that opens it, the attacker it needs and the version that closes it, then explains why the version to run is v0.11.4 rather than the newest version any advisory names. It does not re-cover licence terms, identity setup or audit logging, which our Open WebUI vs LibreChat vs AnythingLLM comparison already handles.
Open WebUI vulnerabilities in 2026: start with the version you run
Ask every instance what it is running. The version endpoint needs no login, so you can script it across every host, including the ones nobody registered with the platform team.
curl -s https://chat.internal.example/api/version
# {"version":"0.11.4","deployment_id":"..."}Then read the answer against the vulnerable ranges. Counting how many active advisory ranges include a given version gives this picture for 25 September 2026:
Read the dates carefully. The 53 advisories were published in four batches (18 on 24 July, 17 on 4 August, 3 on 9 September, 15 on 10 September), but every one of them was already fixed in a shipped release when it went public: 18 in 0.10.0, 17 in 0.11.0, 17 in 0.11.1 and one in 0.9.0. These are disclosure dates, not the dates the bugs appeared, and anyone summarising them as "53 vulnerabilities found in seven weeks" is misreading the feed.
The full set of 164 holds exactly one critical, CVE-2026-44551, an LDAP empty-password authentication bypass scored 9.1, fixed in 0.9.0 in April 2026 and relevant only where LDAP authentication is enabled. Nothing in the July to September window is critical.
| Version you run | Active advisory ranges that include it | Of which high |
|---|---|---|
| 0.9.6 | 46 | 15 |
| 0.10.2 | 34 | 12 |
| 0.11.0 | 17 | 6 |
| 0.11.1, 0.11.3, 0.11.4 | 0 | 0 |
Why the floor is v0.11.4, not the last version named in an advisory
The obvious floor is 0.11.1, because that is where the published ranges stop. Do not use it. The release notes for v0.11.4, v0.11.2, v0.11.1 and v0.11.0 each carry the same passage under Fixed:
This release includes security and access-control fixes. We recommend updating production deployments at your earliest convenience. Not all security fixes in this version may be enumerated in the fixed section. Some may be withheld for a short time to give administrators time to upgrade.
The v0.11.3 hotfix note does not carry it. The project is telling you, in its own words, that a release can contain security fixes the advisory feed has not described yet. The last three batches show how long that gap runs:
A vulnerability scanner keyed to published advisories therefore runs behind the releases by that gap, and a policy of "upgrade when the scanner flags it" leaves you on a version the maintainers already consider superseded for security reasons. Upgrade on the release, not on the advisory. On the post date that means v0.11.4, released on 21 September 2026. We are not claiming v0.11.2 through v0.11.4 fix any specific named advisory; nothing citable said so on 25 September. The recommendation rests on the release notes and the lag pattern.
The README quickstarts use the moving :main tag. Replace it with the release tag so the running version is explicit, reproducible and something a change record can name:
docker pull ghcr.io/open-webui/open-webui:v0.11.4 # or the slim variant (note: slim defaults VECTOR_DB to pgvector) docker pull ghcr.io/open-webui/open-webui:v0.11.4-slim
The same start-with-your-version triage applies to the gateway that often sits between Open WebUI and the models; we walked through it in the LiteLLM proxy security hardening checklist.
# Provider without RFC 7662 introspection (Google, Microsoft Entra ID, GitHub, Feishu): ENABLE_OAUTH_TOKEN_EXCHANGE=False # Provider that supports RFC 7662 introspection, and you need token exchange: ENABLE_OAUTH_TOKEN_EXCHANGE=True # comma-separated client ids you trust (these two are illustrative) OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS=chat-portal,reporting-service # Either way: ENABLE_PYODIDE_FILE_PERSISTENCE=false
Two settings that keep a hole open after you upgrade
On a default install, upgrading closes all 53. Two settings can undo a fix after the upgrade. OAuth token exchange. CVE-2026-70482 (high 8.1, fixed in 0.11.0) lets an attacker holding a provider token for a victim take over the victim's account, because token exchange accepted tokens issued to any client. The fix is opt-in. In the advisory's words: "Upgrading alone is not sufficient. The check is opt-in: with OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS unset the endpoint behaves as it did before." The advisory also says that providers without RFC 7662 introspection, including Google, Microsoft Entra ID, GitHub and Feishu, cannot be restricted this way, and that on those "token exchange has no safe configuration and should be left disabled." Pyodide file persistence. CVE-2026-59214 (high 7.3, fixed in 0.10.0) is a stored web worker XSS through Pyodide code execution. The fix makes browser-side file persistence available only behind ENABLE_PYODIDE_FILE_PERSISTENCE=true, which, per the advisory, "restores the same-origin worker and re-accepts this risk." It defaults to false. Leave it there. Write both settings into the env file explicitly. For token exchange the right value depends on your identity provider:
| Release that fixed the batch | Release date | Advisories published | Lag |
|---|---|---|---|
| v0.10.0 | 29 June 2026 | 18 on 24 July | 25 days |
| v0.11.0 | 27 July 2026 | 17 on 4 August | 8 days |
| v0.11.1 | 25 August 2026 | 17 on 9 and 10 September | 15 to 16 days |
The precondition table: which settings open which advisories
This is the table your change board wants. Thirty advisories need a setting or feature that is off in a fresh v0.11.4 install. Each row names the setting, its default, the advisories it opens, the highest severity among them and the release that closes all of them.
The rows sum to 30: 13 high, 15 medium, 2 low. The other 23 advisories need no non-default setting at all, and the next section deals with them.
To fill in the left column for your own install, check two places. Some keys are read straight from the environment, so the container env is authoritative for them:
docker exec open-webui env | grep -E '^(VECTOR_DB|ENABLE_OAUTH_TOKEN_EXCHANGE|ENABLE_OAUTH_BACKCHANNEL_LOGOUT|AIOHTTP_CLIENT_ALLOW_REDIRECTS|WEBUI_AUTH_TRUSTED_ROLE_HEADER|ENABLE_SCIM|UVICORN_WORKERS|OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS|ENABLE_PYODIDE_FILE_PERSISTENCE)='
# database backend without printing the connection string
docker exec open-webui sh -c 'echo "${DATABASE_URL%%:*}"'No output line for a key means the default applies. If ENABLE_OAUTH_TOKEN_EXCHANGE=True prints and OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS does not, CVE-2026-70482 is still open on v0.11.4. The DATABASE_URL line prints only the scheme, so no password lands in a terminal log; an empty line means the default SQLite database.
Other settings live in the database. With ENABLE_PERSISTENT_CONFIG at its default of True, values saved through the admin panel win over the env file, so the env file can say channels are off while the running instance has them on. The upgrade-time version of that failure is covered in the comparison post's section on upgrades and disconnected networks. Read the live values through the admin config export instead:
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" https://chat.internal.example/api/v1/configs/export \
| jq '{channels: .["channels.enable"], terminals: (.["terminal_server.connections"] // [] | length), tool_servers: (.["tool_server.connections"] // [] | length), web_loader: .["web.loader.engine"], signup: .["ui.enable_signup"], default_role: .["ui.default_user_role"]}'The endpoint needs an admin token and returns a flat dictionary keyed by dotted names. A null means no stored row, so the default applies. The query counts terminal and tool server connections instead of printing them, because connection entries can hold credentials.
| Setting or feature (non-default) | Default at v0.11.4 | Advisories it opens | Highest | Attacker needs | All fixed by |
|---|---|---|---|---|---|
| Terminal server configured | TERMINAL_SERVER_CONNECTIONS empty | 5: CVE-2026-59224, CVE-2026-59221, CVE-2026-70486, CVE-2026-87995, CVE-2026-70490 | High 8.7 | Terminal access; for CVE-2026-70490 a pending or deactivated account | 0.11.1 |
| Channels | ENABLE_CHANNELS False | 5: CVE-2026-59714, CVE-2026-59215, CVE-2026-59222, CVE-2026-70481, CVE-2026-87994 | High 7.1 | Signed-in user or channel member | 0.11.1 |
Outbound fetch: WEB_LOADER_ENGINE=playwright (2), AIOHTTP_CLIENT_ALLOW_REDIRECTS=true (1), admin-added WEB_FETCH_FILTER_LIST entries (1) | Empty, False, no admin entries | 4: CVE-2026-70479, CVE-2026-87996, CVE-2026-88001, CVE-2026-59223 | High 7.7 | Signed-in user | 0.11.1 |
| OAuth token exchange | ENABLE_OAUTH_TOKEN_EXCHANGE False | 3: CVE-2026-70482, CVE-2026-88005, CVE-2026-88006 | High 8.1 | A provider token for the victim, or a user the allowlist or role policy denies | 0.11.1, plus OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS |
| Other SSO modes: OAuth or SCIM on SQLite, SSO role sync, back-channel logout | All off | 3: CVE-2026-87016, CVE-2026-87014, CVE-2026-87011 | High 8.1 | Varies; CVE-2026-87011 needs no account | 0.11.1 |
| Automations granted to users | USER_PERMISSIONS_FEATURES_AUTOMATIONS False | 2: CVE-2026-59226, CVE-2026-70489 | Medium 6.5 | User with automation permission | 0.11.0 |
| Image generation or editing configured | ENABLE_IMAGE_GENERATION, ENABLE_IMAGE_EDIT off | 2: CVE-2026-59227, CVE-2026-70484 | Medium 4.3 | User denied the image permission | 0.11.0 |
| Redis JWT revocation | REDIS_URL empty | 1: CVE-2026-59219 | High 7.1 | A stolen, already revoked JWT | 0.10.0 |
| Models workspace permission for users | USER_PERMISSIONS_WORKSPACE_MODELS_ACCESS False | 1: CVE-2026-59212 | Medium 5.4 | Models access plus a knowledge base read grant | 0.10.0 |
| Folder sharing | Sharing permission off | 1: CVE-2026-70494 | High 8.1 | Write collaborator on a shared folder | 0.11.0 |
| External knowledge connections | None configured | 1: CVE-2026-87998 | High 7.1 | Write grant on an external knowledge base | 0.11.1 |
| Non-default vector store (11 of 15 backends) | VECTOR_DB chroma, pgvector on slim | 1: CVE-2026-87017 | Medium 4.3 | Any user with a tool-capable model | 0.11.1 |
| Two or more tool servers on one request, one using session or OAuth auth | TOOL_SERVER_CONNECTIONS empty | 1: CVE-2026-87015 | Medium 6.8 | Operator of a bearer-auth tool server | 0.11.1 |
What a default install is exposed to
Twenty-three advisories need no non-default setting: 5 high, 15 medium, 3 low. Sorting them by what the attacker needs is more useful than sorting by score.
Every one of the five default-reachable highs carries a condition that narrows it:
No advisory in the window gives an unauthenticated attacker code execution. The server-side code paths in CVE-2026-59214 and CVE-2026-59216 both need an admin, or a user with function or tool permissions, to act or be hijacked.
Five ways one user can stall the instance
Five default-reachable advisories let any signed-in user hang or stall a request: CVE-2026-59220 (skill-mention ReDoS on every chat completion), CVE-2026-70493 (knowledge-search regex backtracking), CVE-2026-88002 (cyclic chat history), CVE-2026-88000 (message deletion in a cyclic chat tree) and CVE-2026-87013 (folder parent cycle). UVICORN_WORKERS defaults to 1, so one stuck request is the whole service. All five are fixed by 0.11.1. Taken together, the default-install exposure is an insider and compromised-account problem. Fifty of the 53 advisories need a signed-in or pending account. For a bank or a hospital that is the threat model that matters anyway: who holds accounts, what they were granted, and how quickly a departed employee's session dies.
| Attacker needs | Count | Advisories | High among them |
|---|---|---|---|
| No account | 2 | CVE-2026-59218 (login timing reveals registered emails), CVE-2026-59715 (unauthenticated Socket.IO collaborative-document handlers) | None |
| An ordinary account, acting alone | 11 | Includes the five hang bugs below, CVE-2026-70485 (NAT64), CVE-2026-87999 (Azure platform channel), CVE-2026-54020 (DNS rebinding) | CVE-2026-70485, CVE-2026-87999 |
| A victim who opens or runs attacker content | 4 | Includes CVE-2026-59214 (Pyodide Run), CVE-2026-70492 (KaTeX stored XSS), CVE-2026-70480 (Vega chart fetch) | CVE-2026-59214, CVE-2026-70492 |
| An object shared with the attacker | 6 | CVE-2026-59216 (note), CVE-2026-59217 and CVE-2026-70488 (knowledge base), CVE-2026-70491 (tool), CVE-2026-87997 (folder), CVE-2026-59225 (arena model) | CVE-2026-59216 |
Features that widen the blast radius: terminals, channels and token exchange
Three features account for 13 of the 30 non-default advisories and 6 of the 13 highs among them. The recommendation is the same for all three: if you do not use the feature, leave it off, and confirm it is off in the persisted config rather than the env file.
Terminal servers
Configuring a terminal server opens 5 advisories, 4 of them high. Two are same-origin XSS through iframes that hardcoded allow-same-origin, one in file preview (CVE-2026-70486, 8.2) and one in port preview (CVE-2026-87995, 8.7), each leading to account takeover. CVE-2026-59224 (8.0) let a user spoof the identity forwarded to the upstream terminal through the X-User-Id header and a WebSocket session id. CVE-2026-59221 (7.7) bypassed the path traversal guard with repeated encoding, an incomplete fix of an earlier advisory. CVE-2026-70490 (medium 6.3) let pending or deactivated accounts open terminal sessions, and deactivation set the role to pending without revoking a JWT that lives for 4 weeks by default under JWT_EXPIRES_IN. Operators who had set a restrictive Content Security Policy through TERMINAL_PROXY_HEADERS were not exposed to either iframe XSS advisory, and for the port preview one a CSP set through CONTENT_SECURITY_POLICY also covered it. That is the argument for setting a CSP on any Open WebUI that fronts a terminal, independent of version.
Channels
ENABLE_CHANNELS defaults to False and opens 5 advisories when on: cross-channel message overwrite through the chat completion API (CVE-2026-59714, high 7.1), private channel messages disclosed through thread binding (CVE-2026-59215), members editing or deleting each other's messages (CVE-2026-70481 and CVE-2026-87994), and the channel members endpoint returning the full user model, including webhook URLs and tool server keys (CVE-2026-59222, medium 6.0). That last one is the one to explain to an auditor: a low-privilege channel member could read credentials that belong to other users.
OAuth token exchange
Three advisories: the account takeover in CVE-2026-70482, a domain allowlist bypass (CVE-2026-88005, fixed in 0.9.0) and a role policy bypass (CVE-2026-88006, fixed in 0.11.1). Here the version does not close the hole by itself, as covered above. One nuance changes exposure on Microsoft's side: Entra ID issues per-application subjects, so the cross-client match in CVE-2026-70482 fails there unless OAUTH_MERGE_ACCOUNTS_BY_EMAIL is enabled or OAUTH_SUB_CLAIM points at a stable claim such as oid. Google, GitHub, Okta and default self-hosted OIDC issue client-stable subjects and were directly affected.
SSO, SQLite and the vector store: exposure you inherited from architecture choices
Some advisories apply because of decisions made at install time for reasons that had nothing to do with security.
CVE-2026-87016 (high 8.1, fixed in 0.11.1) allows sign-in as another user on SQLite, the default database, when OAuth, OIDC or SCIM is enabled. JSON matching compiled to a SQL LIKE, so wildcard characters in the subject claim matched other accounts. PostgreSQL deployments are not affected at all. Deliberate exploitation needs a subject claim the attacker controls, which means an operator pointed OAUTH_SUB_CLAIM at a user-settable claim. The realistic risk is the accidental one: a legitimate subject containing an underscore can match a different account with no attacker involved. The SCIM path needs the SCIM bearer token. If you run SSO on SQLite, this is also a reason to plan the move to PostgreSQL.
CVE-2026-87017 (medium 4.3, fixed in 0.11.1) exposed knowledge bases a user could not otherwise access through the built-in knowledge tool, because 11 of the 15 shipped vector backends ignored the access filter: both Qdrant clients, Elasticsearch, OpenSearch, both Milvus clients, openGauss, Oracle 23ai, Pinecone, S3 Vectors and Weaviate. Chroma, pgvector, MariaDB and Valkey applied it and were never affected, so the default VECTOR_DB (chroma, or pgvector on the slim image) is safe from this one. Teams that pointed Open WebUI at an existing Qdrant or Milvus cluster to share a corpus were exposed. The general lesson, that a retrieval-time permission filter is a control you test rather than trust, is the subject of our post on stale ACLs in RAG and revoked access that still returns documents. The backend behind the portal also has its own CVE history; see self-hosted vector database security hardening.
CVE-2026-87014 (medium 6.5, fixed in 0.11.1) is narrower than its title suggests. An admin demoted through SSO role sync, meaning WEBUI_AUTH_TRUSTED_ROLE_HEADER or OAuth role mapping, kept read and write access to all users' notes, and only over a Socket.IO connection opened while still admin and held open across the demotion. A reconnect, reload or sign-out ended it, and demotions made in the admin panel were never affected.
CVE-2026-87011 (high 7.5, fixed in 0.11.1) is the uncomfortable one. It lets unauthenticated requests stall the server through uncached OIDC fetches in back-channel logout, and the attacker needs only network access and the issuer string. The advisory notes that ENABLE_OAUTH_BACKCHANNEL_LOGOUT is recommended in the Open WebUI hardening documentation, which lists IdP-initiated back-channel logout as a hardening step. A hardening step opened an unauthenticated denial of service until 0.11.1. That hardening guide is useful, but it names no CVE or GHSA and does not map advisories to settings, which is why the table above has to exist in your own runbook.
This pattern predates the batch. CVE-2025-64496 (high 7.3, fixed in 0.6.35) needed Direct Connections, which ships off, and CVE-2026-45672 (high 8.8, fixed in 0.8.12) ran Jupyter code despite ENABLE_CODE_EXECUTION=false. A disable switch is a control only from the version that enforces it; CVE-2026-59227 in this batch repeated the lesson with an image edit route that ignored ENABLE_IMAGE_EDIT=False.
On-prem and regulated deployments: what changes the answer
Running Open WebUI inside your own perimeter changes the answer in three concrete places.
Network egress decides the fetch advisories. Eight advisories in the window involve fetching something the attacker chose. Seven are server-side: CVE-2026-54020 (DNS rebinding), CVE-2026-70485 (NAT64), CVE-2026-87999 (Azure platform channel), the two Playwright loader SSRFs, the redirect bypass and the filter-list bypass (which, per its advisory, never got past the private-IP guard). A host whose outbound traffic is denied at the network layer neutralises all seven regardless of version. The eighth, the Vega chart fetch in CVE-2026-70480, runs in the viewer's browser, so it is bounded by what the workstation can reach. We cover the host-level deny and what it breaks in securing an Ollama server exposed to the internet. v0.11.4 also ships a default fetch filter list of 18 entries, including 169.254.169.254, metadata.google.internal, metadata.azure.com and 168.63.129.16, merged with any WEB_FETCH_FILTER_LIST entries you add. Treat it as a second layer, not the first.
Cloud "private" is not an enclave. CVE-2026-87999 exists only on Azure, and CVE-2026-70485 only on a network that provides NAT64. Neither applies to hosting on your own hardware in a network without a NAT64 gateway. If your "private AI" is a VM in a public cloud tenancy, check both: the Azure one applies on any Azure host, and the NAT64 one on any IPv6 or dual-stack network that translates 64:ff9b::/96. That is a concrete input to the hosting decision.
Disconnected instances cannot watch for updates. ENABLE_VERSION_UPDATE_CHECK defaults to true and calls api.github.com; inside an air-gapped enclave the call fails and the endpoint returns no latest version. Combine that with fixes shipping 8 to 25 days before their advisories, and the patch trigger has to be the release feed watched from a connected machine, followed by a pinned image staged into the enclave under change control. The sneakernet side of that process is the same one we describe in the vLLM air-gapped deployment guide.
Account lifecycle closes the loop. ENABLE_SIGNUP defaults to True and DEFAULT_USER_ROLE to pending, so on a fresh install anyone who reaches the login page can create a pending account. A pending account, newly registered or deactivated back to pending, is the attacker in CVE-2026-70490 (terminals), and CVE-2026-59226 (automations) let a deactivated account's scheduled automations keep running. If identities come from SSO or an admin, set signup off, and check the persisted ui.enable_signup value in the export rather than trusting the env file.
What to check this week
Six steps, each small enough to finish before Friday:
curl -s https://<host>/api/version against every instance, including the ones nobody told you about.ghcr.io/open-webui/open-webui:v0.11.4 (or -slim), stage it, and re-test your SSO login and one retrieval query before promoting it.OAUTH_TOKEN_EXCHANGE_TRUSTED_CLIENT_IDS on a provider with RFC 7662 introspection, or turn it off on any other.UVICORN_WORKERS at 1, or test more workers in staging.More on securing the rest of a private AI stack sits in our AI security guide.
FAQ
Quick answers to the questions this post tends to raise.



