Open WebUI: spoofing
Medium5.4CVE-2026-45396 · Published May 14, 2026 · updated Jul 13, 2026
# Mass Assignment in Feedback Creation Allows User ID Spoofing and Evaluation Data Manipulation ## Summary The `POST /api/v1/evaluations/feedback` endpoint in Open WebUI v0.9.2 is vulnerable to mass assignment via `FeedbackForm`, which uses `model_config = ConfigDict(extra='allow')`. Due to an insecure dictionary merge order in `insert_new_feedback()`, an authenticated attacker can inject a `user_id` field in the request body that overwrites the server-derived value, creating feedback records attributed to any arbitrary user. This corrupts the model evaluation leaderboard (Elo ratings) and enables identity spoofing. ## Details The vulnerability exists in two layers: ### 1. Model Layer , Insecure Dict Merge Order **File:** `backend/open_webui/models/feedbacks.py`, lines 148–160 ```python async def insert_new_feedback( self, user_id: str, form_data: FeedbackForm, db: Optional[AsyncSession] = None ) -> Optional[FeedbackModel]: async with get_async_db_context(db) as db: id = str(uuid.uuid4()) feedback = FeedbackModel( **{ 'id': id, 'user_id': user_id, # ← Server-set from auth token 'versio...
Affected versions
| Package | Affected | Fixed in |
|---|---|---|
| open-webui PyPI | < 0.9.5 | 0.9.5 |
Details and references
# Mass Assignment in Feedback Creation Allows User ID Spoofing and Evaluation Data Manipulation ## Summary The `POST /api/v1/evaluations/feedback` endpoint in Open WebUI v0.9.2 is vulnerable to mass assignment via `FeedbackForm`, which uses `model_config = ConfigDict(extra='allow')`. Due to an insecure dictionary merge order in `insert_new_feedback()`, an authenticated attacker can inject a `user_id` field in the request body that overwrites the server-derived value, creating feedback records attributed to any arbitrary user. This corrupts the model evaluation leaderboard (Elo ratings) and enables identity spoofing. ## Details The vulnerability exists in two layers: ### 1. Model Layer , Insecure Dict Merge Order **File:** `backend/open_webui/models/feedbacks.py`, lines 148–160 ```python async def insert_new_feedback( self, user_id: str, form_data: FeedbackForm, db: Optional[AsyncSession] = None ) -> Optional[FeedbackModel]: async with get_async_db_context(db) as db: id = str(uuid.uuid4()) feedback = FeedbackModel( **{ 'id': id, 'user_id': user_id, # ← Server-set from auth token 'version': 0, **form_data.model_dump(), # ← OVERWRITES 'id', 'user_id', 'version' 'created_at': int(time.time()), 'updated_at': int(time.time()), } ) ``` In Python, when a dictionary literal contains duplicate keys, the **last value wins**. Since `**form_data.model_dump()` appears after `'user_id': user_id`, any `user_id` field in the form data overwrites the authenticated user's ID. ### 2. Schema Layer , `extra='allow'` on Request Form **File:** `backend/open_webui/models/feedbacks.py`, line 106 ```python class FeedbackForm(BaseModel): type: str data: Optional[RatingData] = None meta: Optional[dict] = None snapshot: Optional[SnapshotData] = None model_config = ConfigDict(extra='allow') # ← Accepts arbitrary extra fields ``` The `extra='allow'` config means Pydantic will accept and preserve any extra fields in the request body, including `user_id`, `id`, and `version`. These are then spread into the `FeedbackModel` constructor, overwriting server-set values. ### Contrast with Secure Pattern Other models in the same codebase use the correct ordering. For example, `backend/open_webui/models/functions.py`, line 120: ```python function = FunctionModel(**{ **form_data.model_dump(), # ← Spread FIRST 'user_id': user_id, # ← Server value AFTER → always wins }) ``` And `ModelForm` at `backend/open_webui/models/models.py` uses `extra='ignore'`, which is the strictest approach. ## Impact ### 1. User Identity Spoofing An attacker can create feedback records attributed to any user by specifying their `user_id`. The admin export endpoint (`GET /api/v1/evaluations/feedbacks/export`) and admin list (`GET /api/v1/evaluations/feedbacks/all`) will show the spoofed `user_id` as the feedback author. ### 2. Model Evaluation Leaderboard Manipulation The Elo rating system at `backend/open_webui/routers/evaluations.py` computes model rankings directly from feedback records. An attacker can inject fake rating feedback to: - Artificially inflate ratings for a specific model - Deflate ratings for competitor models - Make organizational model evaluation decisions unreliable ### 3. Record ID Control By injecting a custom `id`, an attacker controls the UUID of the feedback record. While this won't overwrite existing records (primary key constraint), it enables predictable record IDs that could be useful in other attack chains. ## PoC ```python import requests BASE_URL = "http://localhost:8080" # 1. Login as attacker session = requests.Session() login_resp = session.post(f"{BASE_URL}/api/v1/auths/signin", json={ "email": "attacker@example.com", "password": "attackerpass" }) token = login_resp.json()["token"] headers = {"Authorization": f"Bearer {token}"} #
- CVSS 3.1
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
- Severity from
- GitHub (reviewed advisory)
- Weakness
- CWE-915
- Also known as
- CVE-2026-45396, PYSEC-2026-2756
More Open WebUI advisories
All Open WebUI| Date | Advisory | Severity | Fixed in |
|---|---|---|---|
| May 14 | Open WebUI: LDAP and OAuth First-User Race Condition Allows Multiple Admin Accounts | High8.1 | 0.9.0 |
| May 14 | Open WebUI: Jupyter code execution works despite `ENABLE_CODE_EXECUTION=false` , feature gate bypassed | High8.8 | 0.8.12 |
| May 14 | Open WebUI: shared-chat branch ignores access_type, allowing unauthorized file deletion | High8.0 | 0.9.0 |
| May 14 | Open WebUI: Unauthenticated endpoint can trigger embedding generation (cost/DoS) | Medium6.5 | 0.8.0 |
| May 14 | Open WebUI has an Indirect Object Reference (IDOR) in user notes | Medium6.5 | 0.8.11 |
| May 14 | Open WebUI: insecure direct object reference | High8.1 | 0.9.5 |