## Summary The `get_all_models` handlers in `routers/openai.py` and...
Low3.5CVE-2026-59213 · Published Jul 24, 2026 · updated Aug 4, 2026
## Summary 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. ## Impact - **Boundary crossed:** Confidentiality (cross-user). A caller can receive the model list scoped to a *different* security principal than themselves. - A user (or admin, or , depending on endpoint reachability , anonymous caller) who populates the cache causes the next caller within the TTL to receive *that* list rather than their own permission-filtered one. - What's disclosed is the set of models another principal can access, including potentially the existence and naming of mod...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| open-webui PyPI | >= 0.6.27, < 0.10.0 | 0.10.0 |
Details and references
## Summary 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. ## Impact - **Boundary crossed:** Confidentiality (cross-user). A caller can receive the model list scoped to a *different* security principal than themselves. - A user (or admin, or , depending on endpoint reachability , anonymous caller) who populates the cache causes the next caller within the TTL to receive *that* list rather than their own permission-filtered one. - What's disclosed is the set of models another principal can access, including potentially the existence and naming of models restricted from the receiving user. - Exposure is **incidental and timing-dependent**, not attacker-controlled: the leaked entry is whatever the most recent caller populated within `MODELS_CACHE_TTL` (default 1 second), and the attacker cannot select the victim or force a target's list into the cache. ## Affected component - `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. ## Root cause 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. ## Reproduction (default config) 1. On a default deployment, configure at least two users with *different* model-access permissions (e.g. one model restricted to user A). 2. As user A, request the model list (populates the shared cache entry). 3. Within `MODELS_CACHE_TTL` (default 1s), as user B, request the model list. 4. User B receives user A's permission-filtered list, including models B is not permitted to see. ## Remediation Replace `key=` with `key_builder=` at both call sites and adjust the lambda to take the function as its first argument: ```python @cached( ttl=MODELS_CACHE_TTL, key_builder=lambda _func, request, user=None: ( f'openai_all_models_{user.id}' if user else 'openai_all_models' ), ) ```
- CVSS 3.1
- CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:N/A:N
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-524
- Also known as
- CVE-2026-59213, PYSEC-2026-3589
- github.com/open-webui/open-webui/security/advisories/GHSA-3wp3-xxj9-5jqq
- nvd.nist.gov/vuln/detail/CVE-2026-59213
- github.com/open-webui/open-webui/pull/25783
- github.com/open-webui/open-webui/commit/0fc630b34b2899599dabffffa012afd47599aa75
- github.com/open-webui/open-webui
- github.com/open-webui/open-webui/releases/tag/v0.10.0
More Open WebUI advisories
All Open WebUI| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| Jul 24 | open-webui terminal proxy path traversal guard bypass via 9x encoded traversal | High7.7 | 0.10.0 |
| Jul 24 | Open WebUI: Arena task endpoints can bypass underlying model access controls | Medium5.4 | 0.10.0 |
| Jul 24 | Open WebUI: Model meta.knowledge read-only file access can be upgraded to file write/delete | Medium5.4 | 0.10.0 |
| Jul 24 | Open WebUI: server-side request forgery | High8.0 | 0.10.0 |
| Jul 24 | Open WebUI: protection mechanism failure | Medium4.3 | 0.10.0 |
| Jul 24 | Open WebUI: /api/v1/channels/{id}/members exposes full user model including sensitive credentials | Medium | 0.10.0 |