CVE-2026-59213Low· 3.5▾ SunlitOpen WebUI: Cross-user model-list exposure via static cache key in get_all_models (aiocache key= vs key_builder= misuse)
▾ Sunlit zone — Low / medium · no exploitation signal
impact 19.3 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Jul 24.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.3%
0.3% → 0.3%
The get_all_models handlers in routers/openai.py and routers/ollama.py intended to cache their permission-filtered model lists per user, but the @cached decorator was misconfigured: it passed a key= lambda instead of key_builder=. In aiocache 0.12.3 (the pinned version), key= is a static cache key — a callable passed there is used as a constant object, not invoked per call. As a result the per-user key was never computed, and all callers collided onto a single shared cache entry within the TTL window. During that window, one user's permission-filtered model list could be served to a different authenticated user, crossing the per-user authorization boundary.
MODELS_CACHE_TTL (default 1 second), and the attacker cannot select the victim or force a target's list into the cache.backend/open_webui/routers/openai.py — get_all_models (~line 488)backend/open_webui/routers/ollama.py — get_all_models (~line 302)Both decorated with @cached(ttl=MODELS_CACHE_TTL, key=lambda ...). No other @cached(... key=lambda ...) misuse was found elsewhere in the backend.
aiocache 0.12's @cached treats key= as a static key; the per-call hook is key_builder= with signature key_builder(func, *args, **kwargs). Passing a callable to key= uses the callable object itself as a constant key, so every invocation resolved to the same entry and the intended per-user.id namespacing never occurred.
MODELS_CACHE_TTL (default 1s), as user B, request the model list.Replace key= with key_builder= at both call sites and adjust the lambda to take the function as its first argument:
@cached(
ttl=MODELS_CACHE_TTL,
key_builder=lambda _func, request, user=None: (
f'openai_all_models_{user.id}' if user else 'openai_all_models'
),
)
open-webui >= 0.6.27, < 0.10.0Upgrade to a patched release:
open-webui 0.10.0Connected by shared product, vendor, weakness, or advisory.
CVE-2026-59223Medium· 4.3Open WebUI: `WEB_FETCH_FILTER_LIST` host allow/block filter bypassable via URL path and non-label-boundary matching
CVE-2026-59224High· 8.0Open WebUI: Terminal proxy forwards a spoofable, integrity-unbound user identity to the upstream (X-User-Id header and ws_terminal session_id query injection)
CVE-2026-59212Medium· 5.4Open WebUI: Model meta.knowledge read-only file access can be upgraded to file write/delete
CVE-2026-59225Medium· 5.4Open WebUI: Arena task endpoints can bypass underlying model access controls
CVE-2026-59221High· 7.7open-webui terminal proxy path traversal guard bypass via 9x encoded traversal
CVE-2026-59218Medium· 5.3Open WebUI: Account enumeration via observable login timing discrepancy