add security headers for file-preview to prevent cross-site scripting (XSS) injection #20673

Closed
opened 2026-02-21 20:08:24 -05:00 by yindo · 1 comment
Owner

Originally created by @ruanimal on GitHub (Nov 28, 2025).

Self Checks

  • I have read the Contributing Guide and Language Policy.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report, otherwise it will be closed.
  • Please do not modify this template :) and fill in all the required fields.

1. Is this request related to a challenge you're experiencing? Tell me about your story.

The current file preview interface is at risk of XSS injection. If a user uploads malicious HTML, SVG, or XML files, it may trigger various attacks.

There is a risk of XSS injection in the current file preview interface. If a user uploads malicious HTML, SVG, or XML files, it may trigger various attacks.

Reproduction method:

  • Upload a malicious file as a workflow parameter and open the file preview link.

Example file:

alert.svg

xss_test.html

2. Additional context or comments

No response

3. Can you help us with this feature?

  • I am interested in contributing to this feature.
Originally created by @ruanimal on GitHub (Nov 28, 2025). ### Self Checks - [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542). - [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [x] I confirm that I am using English to submit this report, otherwise it will be closed. - [x] Please do not modify this template :) and fill in all the required fields. ### 1. Is this request related to a challenge you're experiencing? Tell me about your story. The current file preview interface is at risk of XSS injection. If a user uploads malicious HTML, SVG, or XML files, it may trigger various attacks. There is a risk of XSS injection in the current file preview interface. If a user uploads malicious HTML, SVG, or XML files, it may trigger various attacks. Reproduction method: - Upload a malicious file as a workflow parameter and open the file preview link. Example file: [alert.svg](https://github.com/user-attachments/assets/178ea947-d247-450e-89cc-c3f4d3af678c) [xss_test.html](https://github.com/user-attachments/files/23822692/xss_test.html) ### 2. Additional context or comments _No response_ ### 3. Can you help us with this feature? - [x] I am interested in contributing to this feature.
yindo added the 💪 enhancement label 2026-02-21 20:08:24 -05:00
yindo closed this issue 2026-02-21 20:08:24 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Nov 28, 2025):

To mitigate XSS in file previews, you should add security headers to the Flask Response objects in the preview endpoints. The most effective headers are:

  • Content-Security-Policy (CSP): Restricts what scripts and resources can run. For file previews, a safe default is Content-Security-Policy: default-src 'none'; sandbox.
  • X-Content-Type-Options: nosniff: Prevents browsers from interpreting files as a different MIME type, which is critical for SVG/HTML/XML.
  • X-Frame-Options: DENY: Prevents the file from being embedded in an iframe, blocking clickjacking and some XSS vectors.
  • Referrer-Policy: no-referrer: Reduces information leakage.

In the Dify codebase, file previews are served in Flask controllers like api/controllers/files/image_preview.py and api/controllers/service_api/app/file_preview.py. Currently, these endpoints set headers like Content-Type and Content-Disposition but do not set any security headers (source).

You can add these headers directly when constructing the Response object, for example:

response.headers['Content-Security-Policy'] = "default-src 'none'; sandbox"
response.headers['X-Content-Type-Options'] = 'nosniff'
response.headers['X-Frame-Options'] = 'DENY'
response.headers['Referrer-Policy'] = 'no-referrer'

For broader coverage, consider using a Flask after_request handler to set these headers on all file preview responses. If you want to be selective (e.g., only for HTML, SVG, XML), check the Content-Type before setting the headers.

There is precedent in the project for disabling HTML preview due to XSS risk, and sandboxed iframes have been discussed as an additional mitigation (discussion). However, adding these headers is a strong first step.

Actionable next steps: update the relevant Flask endpoints to include these headers, test with malicious HTML/SVG/XML files, and verify that browsers block script execution and unsafe rendering.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 28, 2025): <!-- Answer --> To mitigate XSS in file previews, you should add security headers to the Flask Response objects in the preview endpoints. The most effective headers are: - `Content-Security-Policy` (CSP): Restricts what scripts and resources can run. For file previews, a safe default is `Content-Security-Policy: default-src 'none'; sandbox`. - `X-Content-Type-Options: nosniff`: Prevents browsers from interpreting files as a different MIME type, which is critical for SVG/HTML/XML. - `X-Frame-Options: DENY`: Prevents the file from being embedded in an iframe, blocking clickjacking and some XSS vectors. - `Referrer-Policy: no-referrer`: Reduces information leakage. In the Dify codebase, file previews are served in Flask controllers like `api/controllers/files/image_preview.py` and `api/controllers/service_api/app/file_preview.py`. Currently, these endpoints set headers like `Content-Type` and `Content-Disposition` but do not set any security headers ([source](https://github.com/langgenius/dify/blob/a8491c26ea67fbd386a2ca7a5a2b1fa9ba937325/api/controllers/service_api/app/file_preview.py#L26-L186)). You can add these headers directly when constructing the `Response` object, for example: ```python response.headers['Content-Security-Policy'] = "default-src 'none'; sandbox" response.headers['X-Content-Type-Options'] = 'nosniff' response.headers['X-Frame-Options'] = 'DENY' response.headers['Referrer-Policy'] = 'no-referrer' ``` For broader coverage, consider using a Flask `after_request` handler to set these headers on all file preview responses. If you want to be selective (e.g., only for HTML, SVG, XML), check the `Content-Type` before setting the headers. There is precedent in the project for disabling HTML preview due to XSS risk, and sandboxed iframes have been discussed as an additional mitigation ([discussion](https://github.com/langgenius/dify/issues/19159)). However, adding these headers is a strong first step. Actionable next steps: update the relevant Flask endpoints to include these headers, test with malicious HTML/SVG/XML files, and verify that browsers block script execution and unsafe rendering. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/155397ae-905a-444b-aa70-dc4d27635a91?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=To%20mitigate%20XSS%20in%20file%20previews%2C%20you%20should%20add%20security%20headers%20to%20the%20Flask%20Response%20objects%20in%20the%20preview%20endpoints.%20The%20most%20effective%20headers%20are%3A%0A%0A-%20%60Content-Security-Policy%60%20%28CSP%29%3A%20Restricts%20what%20scripts%20and%20resources%20can%20run.%20For%20file%20previews%2C%20a%20safe%20default%20is%20%60Content-Security-Policy%3A%20default-src%20%27none%27%3B%20sandbox%60.%0A-%20%60X-Content-Type-Options%3A%20nosniff%60%3A%20Prevents%20browsers%20from%20interpreting%20files%20as%20a%20different%20MIME%20type%2C%20which%20is%20critical%20for%20SVG/HTML/XML.%0A-%20%60X-Frame-Options%3A%20DENY%60%3A%20Prevents%20the%20file%20from%20being%20embedded%20in%20an%20iframe%2C%20blocking%20clickjacking%20and%20some%20XSS%20vectors.%0A-%20%60Referrer-Policy%3A%20no-referrer%60%3A%20Reduces%20information%20leakage.%0A%0AIn%20the%20Dify%20codebase%2C%20file%20previews%20are%20served%20in%20Flask%20controllers%20like%20%60api/controllers/files/image_preview.py%60%20and%20%60api/controllers/service_api/app/file_preview.py%60.%20Currently%2C%20these%20endpoints%20set%20headers%20like%20%60Content-Type%60%20and%20%60Content-Disposition%60%20but%20do%20not%20set%20any%20security%20headers%20%28%5Bsource%5D%28https%3A//github.com/langgenius/dify/blob/a8491c26ea67fbd386a2ca7a5a2b1fa9ba937325/api/controllers/service_api/app/file_preview.py%23L26-L186%29%29.%0A%0AYou%20can%20add%20these%20headers%20directly%20when%20constructing%20the%20%60Response%60%20object%2C%20for%20example%3A%0A%0A%60%60%60python%0Aresponse.headers%5B%27Content-Security-Policy%27%5D%20%3D%20%22default-src%20%27none%27%3B%20sandbox%22%0Aresponse.headers%5B%27X-Content-Type-Options%27%5D%20%3D%20%27nosniff%27%0Aresponse.headers%5B%27X-Frame-Options%27%5D%20%3D%20%27DENY%27%0Aresponse.headers%5B%27Referrer-Policy%27%5D%20%3D%20%27no-referrer%27%0A%60%60%60%0A%0AFor%20broader%20coverage%2C%20consider%20using%20a%20Flask%20%60after_request%60%20handler%20to%20set%20these%20headers%20on%20all%20file%20preview%20responses.%20If%20you%20want%20to%20be%20selective%20%28e.g.%2C%20only%20for%20HTML%2C%20SVG%2C%20XML%29%2C%20check%20the%20%60Content-Type%60%20before%20setting%20the%20headers.%0A%0AThere%20is%20precedent%20in%20the%20project%20for%20disabling%20HTML%20preview%20due%20to%20XSS%20risk%2C%20and%20sandboxed%20iframes%20have%20been%20discussed%20as%20an%20additional%20mitigation%20%28%5Bdiscussion%5D%28https%3A//github.com/langgenius/dify/issues/19159%29%29.%20However%2C%20adding%20these%20headers%20is%20a%20strong%20first%20step.%0A%0AActionable%20next%20steps%3A%20update%20the%20relevant%20Flask%20endpoints%20to%20include%20these%20headers%2C%20test%20with%20malicious%20HTML/SVG/XML%20files%2C%20and%20verify%20that%20browsers%20block%20script%20execution%20and%20unsafe%20rendering.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/28909)
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#20673