mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-11 10:34:13 -05:00
[PR #24508] [MERGED] fix: prevent mass-assignment user_id spoofing in POST /api/v1/evaluations/feedback #131357
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/open-webui/open-webui/pull/24508
Author: @Classic298
Created: 5/9/2026
Status: ✅ Merged
Merged: 5/10/2026
Merged by: @tjbck
Base:
dev← Head:fix/feedback-form-mass-assignment📝 Commits (2)
234fb56fix: prevent mass-assignment user_id spoofing in POST /api/v1/evaluations/feedback197c8d8chore: trim comments📊 Changes
1 file changed (+4 additions, -2 deletions)
View changed files
📝
backend/open_webui/models/feedbacks.py(+4 -2)📄 Description
Two independent gaps in backend/open_webui/models/feedbacks.py let an authenticated caller forge the
user_id(andid,version) on a new feedback record submitted to POST /api/v1/evaluations/feedback:FeedbackFormdeclaredmodel_config = ConfigDict(extra='allow'), so Pydantic preserved any extra fields supplied in the request body — includinguser_id,id,version. The form is the public input boundary for the endpoint and should not accept unknown fields.In
insert_new_feedback, the dict literal placed**form_data.model_dump()AFTER'id': id,'user_id': user_id,'version': 0. Python dict-literal duplicate-key resolution is last-wins, so any of those fields present inform_dataoverwrote the server-derived values.Combined effect: a regular user could POST a feedback record with an arbitrary
user_id, attributing the rating to any other user. The Elo leaderboard at backend/open_webui/routers/evaluations.py computes model rankings from these records, and the admin export(GET /api/v1/evaluations/feedbacks/export) and admin list (GET /api/v1/evaluations/feedbacks/all) display the spoofed attribution.
Two fixes, defense-in-depth:
FeedbackForm: switch
extra='allow'toextra='ignore'so Pydantic drops unknown fields at parse time. Sub-models (RatingData / MetaData / SnapshotData) intentionally keepextra='allow'because their contents are deliberately schema-flexible — the spoofing surface was the form, not the sub-payloads.insert_new_feedback: spread
form_data.model_dump()first, then overlay server-controlled fields (id,user_id,version,created_at,updated_at) so the explicit keys win on duplicate-key resolution regardless of what reaches the function. Matches the secure pattern already used in backend/open_webui/models/functions.py:120.Contributor License Agreement
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.