CVE Request — GHSA-jx8r-j32j-q3mq
Description
Reflected Cross-Site Scripting (XSS) vulnerability in the embedded MCP HTTP server of next-ai-draw-io. The server interpolates the ?mcp= query parameter directly into a <script> block and into raw HTML without sanitization or encoding, allowing arbitrary JavaScript execution in the localhost origin when a victim visits a crafted URL.
Affected Product
| Field |
Value |
| Ecosystem |
npm |
| Package |
@next-ai-drawio/mcp-server |
| Affected versions |
<= 0.2.1 (bundled in next-ai-draw-io <= 0.4.16) |
| Patched versions |
(pending — to be confirmed once fix is released) |
Weakness
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-Site Scripting')
Severity (CVSS v3.1)
- Score: 6.1 (Moderate)
- Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N
Summary
The MCP embedded HTTP server interpolates the ?mcp= query parameter directly into a <script> block and into raw HTML without any sanitization or encoding. An attacker who can trick a user into visiting a crafted http://localhost:<port>/?mcp=… URL causes arbitrary JavaScript to execute in the localhost origin, where it can read and exfiltrate every diagram session stored by the server.
Details
packages/mcp-server/src/http-server.ts extracts the query parameter at line 264:
// line 264
const sessionId = url.searchParams.get("mcp") || ""
sessionId is then interpolated unescaped in two places:
Sink 1 — Inside a <script> block (line 700, JS injection)
// line 700 — inside getHtmlPage(sessionId)
const sessionId = "${sessionId}";
A value such as ";alert(1);// closes the string literal, injects arbitrary statements, and comments out the remainder of the line.
Sink 2 — Inside HTML markup (line 638, HTML injection)
// line 638
${sessionId ? `<span class="session">${sessionId.slice(-8)}</span>` : ""}
A value containing <img src=x onerror=…> is rendered verbatim into the page.
Neither encodeURIComponent, encodeHTML, nor any escaping function is applied before either interpolation.
Proof of Concept
Prerequisites: the MCP HTTP server is running locally (default port range 6002–6020, or any custom port).
- Identify the port (displayed in the VS Code sidebar or MCP server logs).
- Open the following URL in any browser while the server is running:
http://localhost:<PORT>/?mcp=%22%3Balert(document.domain)%3B%2F%2F
URL-decoded payload: ";alert(document.domain);//
- The page loads and the browser shows an
alert() dialog displaying the origin (http://localhost:<PORT>) without any user interaction beyond navigating to the URL.
Delivery vector: embed the URL inside a malicious webpage hosted on an attacker-controlled domain:
<iframe src="http://localhost:6002/?mcp=%22%3Balert(document.origin)%3B%2F%2F"></iframe>
Or via window.open(…). When the victim visits the page while the MCP server is running, the payload executes automatically.
Impact
| Dimension |
Detail |
| Who is affected |
Any user running @next-ai-drawio/mcp-server who visits an attacker-controlled webpage while the MCP HTTP server is active |
| Attacker prerequisite |
Victim visits a malicious page — no credentials or local access required |
| Consequence |
Injected JavaScript executes in the localhost origin and can call any /api/* endpoint (read all diagram XML, session history, model configuration) and exfiltrate data to an external server without further user interaction |
Recommended Fix
HTML-encode sessionId before any interpolation into HTML or JavaScript:
function escapeHtml(s: string): string {
return s.replace(/&/g, "&").replace(/</g, "<")
.replace(/>/g, ">").replace(/"/g, """)
.replace(/'/g, "'")
}
function escapeJs(s: string): string {
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')
.replace(/'/g, "\\'").replace(/</g, "\\x3C")
.replace(/\r?\n/g, "\\n")
}
// line 700 — JS context
const sessionId = "${escapeJs(sessionId)}";
// line 638 — HTML context
${sessionId ? `<span class="session">${escapeHtml(sessionId.slice(-8))}</span>` : ""}
Reporter: @HK4zCzi (Hồ Việt Khánh)
CVE Request — GHSA-jx8r-j32j-q3mq
Description
Reflected Cross-Site Scripting (XSS) vulnerability in the embedded MCP HTTP server of
next-ai-draw-io. The server interpolates the?mcp=query parameter directly into a<script>block and into raw HTML without sanitization or encoding, allowing arbitrary JavaScript execution in thelocalhostorigin when a victim visits a crafted URL.Affected Product
@next-ai-drawio/mcp-servernext-ai-draw-io<= 0.4.16)Weakness
CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-Site Scripting')
Severity (CVSS v3.1)
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:NSummary
The MCP embedded HTTP server interpolates the
?mcp=query parameter directly into a<script>block and into raw HTML without any sanitization or encoding. An attacker who can trick a user into visiting a craftedhttp://localhost:<port>/?mcp=…URL causes arbitrary JavaScript to execute in thelocalhostorigin, where it can read and exfiltrate every diagram session stored by the server.Details
packages/mcp-server/src/http-server.tsextracts the query parameter at line 264:sessionIdis then interpolated unescaped in two places:Sink 1 — Inside a
<script>block (line 700, JS injection)A value such as
";alert(1);//closes the string literal, injects arbitrary statements, and comments out the remainder of the line.Sink 2 — Inside HTML markup (line 638, HTML injection)
A value containing
<img src=x onerror=…>is rendered verbatim into the page.Neither
encodeURIComponent,encodeHTML, nor any escaping function is applied before either interpolation.Proof of Concept
Prerequisites: the MCP HTTP server is running locally (default port range 6002–6020, or any custom port).
URL-decoded payload:
";alert(document.domain);//alert()dialog displaying the origin (http://localhost:<PORT>) without any user interaction beyond navigating to the URL.Delivery vector: embed the URL inside a malicious webpage hosted on an attacker-controlled domain:
Or via
window.open(…). When the victim visits the page while the MCP server is running, the payload executes automatically.Impact
@next-ai-drawio/mcp-serverwho visits an attacker-controlled webpage while the MCP HTTP server is activelocalhostorigin and can call any/api/*endpoint (read all diagram XML, session history, model configuration) and exfiltrate data to an external server without further user interactionRecommended Fix
HTML-encode
sessionIdbefore any interpolation into HTML or JavaScript:Reporter: @HK4zCzi (Hồ Việt Khánh)