MCPSafe.io
RegistryThreatsMethodologyDocsPricingScanSign in
MCPSafe.io

Security checks for MCP servers — public packages and private repos, fast or deep.

Legal

Privacy PolicyCookie PolicyTerms of ServiceSecurity disclosure

Resources

State of MCP SecuritySupportSystem statusMade in Germany 🇩🇪

© 2026 MCPSafe. All rights reserved.

GDPR — Privacy Policy
← Threat Catalog

Interaction & Data Flow

Unescaped HTML in tool output

HIGHCWE: CWE-79Rule: MCP-222

An MCP tool returns content with raw HTML tags built from caller- or model-supplied input — clients that render HTML can execute scripts, load attacker images, or exfiltrate via DOM events.

What it is

MCP tool output is typed as text or content blocks, but some clients render Markdown and embedded HTML. A `<img onerror=fetch(...)>` snippet returned in a tool's text payload is XSS if the renderer evaluates it. The defense is to either strip HTML before returning, or escape the output's HTML-special characters.

Why it matters for MCP

Different MCP clients have different rendering behaviors — some are strict text, some pass Markdown through, some allow embedded HTML for richer UIs. A tool author can't assume strict text. Treating returned content as potentially-rendered HTML is the safe default.

Vulnerable example

example.js
1
server.tool("format_alert", { msg: z.string() }, async ({ msg }) => {
2
  return { content: [{ type: "text", text: `<div class="alert">${msg}</div>` }] };
3
});

Secure example

example.js
1
function escapeHtml(s) {
2
  return s.replace(/[&<>"']/g, (c) => ({
3
    "&": "&amp;", "<": "&lt;", ">": "&gt;", '"': "&quot;", "'": "&#39;",
4
  }[c]));
5
}
6
7
server.tool("format_alert", { msg: z.string() }, async ({ msg }) => {
8
  return { content: [{ type: "text", text: `<div class="alert">${escapeHtml(msg)}</div>` }] };
9
});

How MCPSafe detects this

MCPSafe flags tool returns whose text content includes literal HTML tags (`<div>`, `<a>`, `<img>`, `<script>`, `<iframe>`) interpolated with handler parameters via f-string / template literals / concat. Returns that route the parameter through `escapeHtml`, `escape`, `DOMPurify`, or `html.escape` are exempted.

See the full threat catalog for every documented detection.

Further reading

  • OWASP XSS Prevention Cheat Sheet
  • CWE-79: Cross-site Scripting

Scan an MCP server for this issue

MCPSafe runs this check — and every other rule in the catalog — on any MCP server you paste in.

Scan now