mirror of
https://github.com/open-webui/open-webui.git
synced 2026-07-16 06:03:26 -05:00
[PR #24373] [CLOSED] fix: harden file serving endpoints against stored XSS #98662
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/24373
Author: @SebTardif
Created: 5/5/2026
Status: ❌ Closed
Base:
dev← Head:fix/file-serving-xss-hardening📝 Commits (2)
fd83612security: harden file serving endpoints against stored XSSaddc526security: address review feedback on file serving XSS hardening📊 Changes
1 file changed (+62 additions, -14 deletions)
View changed files
📝
backend/open_webui/routers/files.py(+62 -14)📄 Description
Pull Request Checklist
Before submitting, make sure you've checked the following:
devbranch./content/htmlendpoint still renders HTML but with CSP sandbox blocking script execution.dev, two clean commits.fix:Changelog Entry
Description
Harden file-serving endpoints against stored XSS by validating content types against a safe allowlist and adding security headers. Previously, an attacker could upload a file with
Content-Type: text/htmlcontaining malicious scripts, and any authenticated user viewing the file would execute the scripts under the app's origin.Added
SAFE_INLINE_CONTENT_TYPESallowlist for content types safe to serve inline (images, PDF, plain text, audio, video)_safe_content_type()helper that validates and normalizes content types against the allowlistChanged
GET /{id}/contentnow validates content type against allowlist; unsafe types forced toapplication/octet-stream+ attachment downloadGET /{id}/content/htmlnow includesContent-Security-Policy: sandboxheader blocking script executionGET /{id}/content/{file_name}now explicitly setsmedia_type=application/octet-streamX-Content-Type-Options: nosniffDeprecated
Removed
Fixed
Content-Type: text/htmlno longer results in inline HTML renderingSecurity
X-Content-Type-Options: nosniffprevents MIME-sniffing attacksBreaking Changes
/{id}/contentwill now download instead of displaying inline. SVGs loaded via<img>tags in the frontend are unaffected since browsers disable scripting in that context.text/html,application/javascript) will now force-download instead of rendering inline.Additional Information
/content/htmlendpoint is already restricted to files owned by admin-role users (line 724 check), but in multi-admin deployments a compromised admin could target other admins. The CSP sandbox provides defense-in-depth.users.pyandchannels.pyprofile image endpoints also decode data URIs with user-controlled media types — these are out of scope for this PR but could be addressed separately.Contributor License Agreement
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.