Feb 14, 2026·6 min read·47 visits
The `beautiful-mermaid` library, used to render Mermaid diagrams as SVGs, failed to sanitize user-supplied style attributes. Attackers can inject malicious payloads into `fill` or `stroke` properties, breaking out of the SVG XML structure to execute XSS. Fixed in version 0.1.3.
A critical flaw in the `beautiful-mermaid` library allows attackers to weaponize flowcharts and diagrams. By injecting malicious CSS strings into style definitions, adversaries can break out of SVG attributes and execute arbitrary JavaScript. This vulnerability transforms a harmless documentation tool into a vehicle for Cross-Site Scripting (XSS), affecting all versions prior to 0.1.3.
Mermaid diagrams are the darling of the developer documentation world. They turn cryptic text into beautiful flowcharts, sequence diagrams, and Gantt charts. The beautiful-mermaid library exists to take that text and render it into high-fidelity SVGs, perfect for embedding in websites or documentation portals. It promises "beautiful" rendering, but under the hood, it was doing something ugly: trusting user input blindly.
Imagine you are building a documentation platform. You allow users to submit Mermaid graphs to explain their microservices architecture. You render these server-side or client-side using beautiful-mermaid. It seems harmless enough—after all, it's just boxes and arrows, right? Wrong. In the security world, if you are building HTML or XML strings by mashing variables together without sanitization, you aren't building a renderer; you're building a vulnerability.
CVE-2026-26226 is the classic tale of convenience over security. The library treated style attributes like color, fill, and stroke as pure aesthetic choices, never expecting that someone might try to paint a box with a shade of " onload="alert(1). This oversight turns every diagram into a potential landmine for Cross-Site Scripting (XSS).
The root cause of this vulnerability is a fundamental misunderstanding of how to safely construct XML (and by extension, SVG) documents. There are two ways to build a DOM element: you can use a DOM API (like document.createElement), which naturally handles encoding, or you can build a massive string and hope for the best. beautiful-mermaid chose the latter.
In src/renderer.ts, the library parses the Mermaid syntax to extract node styles. If a user defines a specific style for a node—say, making it red—the library captures that string. The fatal error occurred when the library took those captured strings and interpolated them directly into a template literal to form the SVG output.
It didn't care what was in the string. It didn't look for quotes, angle brackets, or escape characters. It just pasted the value directly into the fill="..." attribute of the SVG string. This is the XML equivalent of SQL injection. The browser parser doesn't know that the attacker's double-quote meant "end of the attribute value." It just sees a closed attribute and a new, malicious instruction following immediately after.
Let's look at the crime scene in src/renderer.ts. The code was responsible for taking style properties and applying them to the SVG elements. Here is the vulnerable logic before the patch:
// Vulnerable: Direct interpolation of user input
const fill = inlineStyle?.fill ?? 'var(--_node-fill)'
const stroke = inlineStyle?.stroke ?? 'var(--_node-stroke)'
const sw = inlineStyle?.['stroke-width'] ?? String(STROKE_WIDTHS.innerBox)
// Later, this is used in a template literal:
// return `<rect fill="${fill}" stroke="${stroke}" ... />`If inlineStyle.fill is controlled by the user, they control the raw HTML output. The fix, introduced in version 0.1.3, is a textbook application of output encoding. The developers wrapped the tainted variables in an escapeXml function before interpolation:
// Fixed: Sanitizing the input before interpolation
const fill = escapeXml(inlineStyle?.fill ?? 'var(--_node-fill)')
const stroke = escapeXml(inlineStyle?.stroke ?? 'var(--_node-stroke)')
const sw = escapeXml(inlineStyle?.['stroke-width'] ?? String(STROKE_WIDTHS.innerBox))This simple change ensures that a double quote " becomes ", preventing the attacker from breaking out of the attribute context. It converts a weaponized string back into a harmless (albeit likely invalid) color value.
Exploiting this is trivially easy once you understand the underlying string concatenation. We don't need complex memory corruption or race conditions; we just need to balance some quotes. The attack vector typically involves the style directive in Mermaid syntax, which allows applying CSS to specific nodes.
Scenario 1: The Event Handler Injection
We want to inject onmouseover="alert(1)". The target code looks roughly like <rect fill="${USER_INPUT}" ... />. If we set our fill color to red" onmouseover="alert(1), the rendered SVG becomes:
<rect fill="red" onmouseover="alert(1)" ... />The browser sees a red rectangle that executes JavaScript when you hover over it.
The Payload:
Scenario 2: The Element Injection
If we want to be louder, we can close the rect tag entirely and start a new script tag. We set the fill to red"/><script>alert(origin)</script><rect fill="x.
The Payload:
This results in a valid SVG structure that includes an inline script block, executing immediately upon rendering in many contexts (though modern CSPs might block inline scripts, the event handler vector remains potent).
While the CVSS score is a moderate 5.3 (primarily because user interaction is usually required to view the diagram, and the scope is limited to the browser), the practical impact can be severe depending on the implementation. This is a classic stored XSS vector.
If a developer uses beautiful-mermaid to render user-generated content (like comments, wiki pages, or issue trackers) server-side and serves the resulting SVG, they are serving weaponized content. SVGs are powerful; they are essentially XML documents that can contain scripts, external object references, and more.
Successful exploitation means an attacker can:
Since this library is likely used in documentation tools or dashboards, the victims are often privileged users (developers, admins) viewing internal diagrams, making the target value high.
The remediation is straightforward: stop trusting strings. The maintainers of beautiful-mermaid released version 0.1.3 which includes the necessary escaping logic. If you are using this library, you need to upgrade immediately.
> [!TIP]
> Action Item: Run npm list beautiful-mermaid or bun pm ls to check your version. If it is < 0.1.3, update it.
If you cannot update for some reason (perhaps you enjoy living on the edge), you must implement a strict Content Security Policy (CSP). A CSP that forbids unsafe-inline scripts and restricts object-src can mitigate the impact of the XSS, preventing the execution of the injected JavaScript even if the HTML is malformed.
However, the only true fix is the patch. Sanitization is hard; don't try to write your own regex to strip quotes. Use the vendor's fix which properly encodes XML entities.
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:P/VC:L/VI:L/VA:N/SC:L/SI:L/SA:N| Product | Affected Versions | Fixed Version |
|---|---|---|
beautiful-mermaid lukilabs | < 0.1.3 | 0.1.3 |
| Attribute | Detail |
|---|---|
| CWE | CWE-79 (XSS) |
| CVSS v4.0 | 5.3 (Medium) |
| Attack Vector | Network (Payload delivery) |
| Privileges Required | None |
| User Interaction | Passive (Viewing diagram) |
| Exploit Status | PoC Available |
Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
A critical stored Cross-Site Scripting (XSS) vulnerability was identified in Froxlor server administration software panel before version 2.3.8. Authenticated customers with DNS editor privileges can inject malicious JavaScript into DNS TXT records. Because the application processes these values via a raw formatting callback without context-aware HTML entity encoding, the payload executes in the security context of administrative users who view the affected domain's DNS zones.
An authenticated administrator with privileges to manage admin accounts (such as change_serversettings) can execute arbitrary SQL commands via a second-order SQL injection vulnerability. The flaw resides in Froxlor's administrative API endpoints, specifically during the handling of IP address mapping parameters which are stored as serialized arrays and later interpolated without sanitization into active database queries. This vulnerability allows high-privileged administrative attackers to compromise the database. By injecting a payload into administrative profile metadata, an attacker can extract sensitive credentials, manipulate backend settings, or potentially disrupt database integrity. The vulnerability affects all versions of Froxlor prior to 2.3.8.
CVE-2026-54543 is a DNS Resource Record (RR) Injection vulnerability in Froxlor, an open-source server administration control panel. Prior to version 2.3.8, the DomainZones.add API command failed to perform strict sanitization and validation on the user-controlled record (label) and type parameters before serializing them into BIND-compatible zone files. An authenticated customer with DNS zone management permissions can inject control characters, breaking out of the original record context to define unauthorized resource records within managed zones.
CVE-2026-42533 is a critical security vulnerability discovered in NGINX Open Source, NGINX Plus, NGINX Ingress Controller, and related products, referred to as the 'Two-Pass Capture-Clobbering' bug. The flaw is situated within NGINX's internal evaluation engine when handling complex variables, exposing a heap-based buffer overflow and information leak when a configuration chains regular expression-based map directives with numbered capture groups. An unauthenticated remote attacker can exploit this weakness by transmitting crafted HTTP requests to trigger remote code execution or defeat ASLR.
Froxlor prior to version 2.3.8 contains a high-severity architectural flaw where the standalone lib/ajax.php entry point bypasses the centralized request validation in lib/init.php. Unauthenticated remote attackers can leverage Cross-Site Request Forgery (CSRF) to induce authenticated administrators to submit forged requests that modify API key whitelists and expiration dates, potentially yielding persistent, out-of-band administrative control.
An insecure data retrieval flaw in the Froxlor server administration panel API allows authenticated remote attackers to retrieve unredacted bcrypt password hashes and Base32-encoded Time-Based One-Time Password (TOTP) seeds. Affected endpoints include several 'get' and 'listing' handlers for customers, administrators, and FTP accounts. Utilizing these leaked parameters, attackers can crack the password hashes offline and concurrently generate valid second-factor authentication codes to completely bypass access controls.