
CVE-2026-9811 is a Stored Cross-Site Scripting (Stored XSS) vulnerability affecting Mautic 7 (versions 7.0.0 through 7.1.1).
CVE-2026-9811 is a Stored Cross-Site Scripting (Stored XSS) vulnerability affecting Mautic 7 (versions 7.0.0 through 7.1.1).The vulnerability exists in the Project Selector component, where project names returned via an AJAX request are inserted into the page without proper output encoding or sanitization. An authenticated user with permission to create projects can store a malicious JavaScript payload in a project name. When another administrator later opens an entity editor containing the project selector, the malicious script executes in their browser.
Property Value Product Mautic Affected Versions 7.0.0 – 7.1.1 Fixed Version 7.1.2 Component Project Selector Vulnerability Type Stored Cross-Site Scripting (XSS)
The application stores project names supplied by authenticated users and later retrieves them through an AJAX endpoint. When rendering the project selector, the application inserts these values directly into the DOM as HTML option elements without escaping or sanitizing the content.
Conceptually:
User creates project
│
▼
Project name stored in database
│
▼
AJAX returns project name
│
▼
Inserted into DOM without sanitization
│
▼
Browser executes embedded JavaScript
Because the application trusts stored data, malicious JavaScript executes whenever another privileged user loads the vulnerable page.
Attacker
│
▼
Creates a project with a malicious JavaScript payload as its name
│
▼
Payload is stored in the database
│
▼
Administrator opens an entity editor
│
▼
AJAX request retrieves project names
│
▼
Application inserts project name into the DOM without encoding
│
▼
Browser executes the malicious script
│
▼
Attacker gains actions within the administrator's session
An attacker with permission to create projects creates a project whose name contains a malicious JavaScript payload.
Later, an administrator edits another entity that includes the Project Selector. The selector loads project names via AJAX and inserts them directly into the page. Because the project name is not sanitized, the browser executes the embedded script with the administrator's privileges.
Imagine Mautic has a form like this:
POST /projects/create HTTP/1.1
Content-Type: application/x-www-form-urlencoded
projectName=Marketing Campaign
description=Email Campaign
The project is saved as:
Marketing Campaign
Step 2: Attacker Creates a Project
Instead of a normal name, the attacker enters HTML containing a harmless JavaScript event:
POST /projects/create HTTP/1.1
Content-Type: application/x-www-form-urlencoded
projectName=<img src="https://raw.githubusercontent.com/aj2108/cve-2026-9811/main/x" onerror="console.log('XSS Demo')">
description=Test
The database now stores exactly that string.
Step 3: AJAX Returns the Stored Value
Later, an administrator opens a page that loads projects.
AJAX response:
{
"id": 7,
"projectName": ""
}
Step 4: Vulnerable JavaScript
Suppose the application does this:
const project = response.projectName;
document.getElementById("projects").innerHTML +=
`<option>${project}</option>`;
The browser sees:
<option>
<img src="https://raw.githubusercontent.com/aj2108/cve-2026-9811/main/x" onerror="console.log('XSS Demo')">
</option>
Since the application inserted the string as HTML rather than text, the browser parses it as an actual element. The image fails to load (src="x"), causing the onerror handler to execute.
Successful exploitation may allow an attacker to:
| Metric | Score |
|---|---|
| CVSS v3.1 (CNA) | 5.4 (Medium) |
NVD has not yet published its own CVSS assessment for this CVE.
Note: The vendor has not published the exact vulnerable source code. The following example illustrates the vulnerability pattern only.
// Data returned from AJAX
const project = response.projectName;
// Unsafe: inserted directly into the DOM
document.getElementById("projectSelector").innerHTML +=
`<option>${project}</option>`;
The project name originates from user input but is inserted into the page without HTML encoding. If the stored value contains HTML or JavaScript, the browser interprets it as executable content instead of plain text.
const option = document.createElement("option");
// Safe: assign as text, not HTML
option.textContent = response.projectName;
document.getElementById("projectSelector").appendChild(option);
Or, if HTML output is unavoidable, ensure proper output encoding before insertion.
Using textContent (or an equivalent safe API) ensures that any special characters are treated as plain text rather than executable HTML or JavaScript. Even if a malicious project name is stored in the database, it will be displayed literally instead of being executed.