mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-11 04:50:11 +02:00
fix: per-user model cache used static key= (cross-user model exposure) (#25783)
routers/openai.py and routers/ollama.py decorated get_all_models with `@cached(key=lambda _, user: ...)`. In aiocache 0.12, `key=` is a STATIC cache key: get_cache_key returns `self.key` verbatim (the lambda object) without calling it, so every caller collides to ONE shared entry within the TTL. The intended per-user namespacing never happened — one user's permission-filtered model list could be served to another user (or an anonymous caller) during the cache window. The per-call hook is `key_builder=` (called as key_builder(func, *args, **kwargs)). Switch both sites to key_builder with a (func, request, user=None) signature so the key is built per call. user=None mirrors ollama's optional-user signature and stays correct whether user is passed positionally, as a kwarg, or omitted. Verified offline: old form returns the same key object for distinct users (collision); new form yields distinct openai_all_models_<id> / ollama_all_models_<id> keys, and the unauthenticated base key when no user. These two were the only @cached(key=lambda ...) sites in the backend.
This commit is contained in:
@@ -336,7 +336,9 @@ def resolve_api_config(api_configs: dict, idx: int, url: str) -> dict:
|
||||
|
||||
@cached(
|
||||
ttl=MODELS_CACHE_TTL,
|
||||
key=lambda _, user: f'ollama_all_models_{user.id}' if user else 'ollama_all_models',
|
||||
# key_builder (not key) is the per-call hook in aiocache 0.12; `key=` is a
|
||||
# static key, so a `key=lambda` collapsed every caller to one shared entry.
|
||||
key_builder=lambda _func, request, user=None: f'ollama_all_models_{user.id}' if user else 'ollama_all_models',
|
||||
)
|
||||
async def get_all_models(request: Request, user: UserModel | None = None):
|
||||
"""Aggregate model tags from every enabled Ollama backend."""
|
||||
|
||||
@@ -522,7 +522,9 @@ async def get_filtered_models(models, user, db=None):
|
||||
|
||||
@cached(
|
||||
ttl=MODELS_CACHE_TTL,
|
||||
key=lambda _, user: f'openai_all_models_{user.id}' if user else 'openai_all_models',
|
||||
# key_builder (not key) is the per-call hook in aiocache 0.12; `key=` is a
|
||||
# static key, so a `key=lambda` collapsed every caller to one shared entry.
|
||||
key_builder=lambda _func, request, user=None: f'openai_all_models_{user.id}' if user else 'openai_all_models',
|
||||
)
|
||||
async def get_all_models(request: Request, user: UserModel) -> dict[str, list]:
|
||||
log.info('get_all_models()')
|
||||
|
||||
Reference in New Issue
Block a user