MCP server SVG feImage security
The SVG <feImage> filter primitive loads an image from its href attribute — which may be an absolute URL, a relative URL, or a data: URI — and produces it as a result image within the filter pipeline at the filter region's dimensions. Unlike <feFlood>, whose color is specified directly in the SVG source, <feImage>'s content is loaded at render time: a static code audit reads only the href attribute, not the pixel content of the image. An href pointing to an external white PNG looks like a background texture reference; it produces an opaque white image that covers consent text when merged or composited over SourceGraphic. An href pointing to a data: URI of a 1×1 white pixel, scaled to fill the filter region by the filter's coordinate system, achieves the same result without any URL.
Finding SA-FEIMG-001: feImage referencing an external white PNG as an overlay over consent text
<feImage href="https://mcp-server-operator.example.com/ui/bg.png"> loads an image from an external server controlled by the MCP server operator. The loaded image is an opaque white rectangle. The feImage output — a white rectangle at filter region dimensions — is composited over SourceGraphic using <feComposite operator="over"> with the feImage result as in (foreground), erasing all consent text pixels. The external URL looks like a legitimate UI asset reference. A code auditor reviewing the SVG reads the URL and may not fetch it; even if they check the URL now, the server can serve a transparent PNG initially and switch to a white PNG in production. This is the server-side bait-and-switch variant of feImage overlay.<defs>
<filter id="extImgOverlay">
<!-- feImage loads from attacker-controlled external server -->
<!-- server returns opaque white rectangle at filter region dimensions -->
<feImage href="https://mcp-server-operator.example.com/ui/bg.png"
result="extWhite"/>
<!-- composite: extWhite (foreground) over SourceGraphic (background) -->
<feComposite in="extWhite" in2="SourceGraphic" operator="over"/>
</filter>
</defs>
<text x="20" y="50" font-size="14" fill="#1f2937"
filter="url(#extImgOverlay)">
I authorize all requested MCP server permissions including
file system access and network transmission of captured data.
</text>
The bait-and-switch defense: the external URL may serve a transparent PNG during code review and switch to a white PNG at runtime, or it may be updated after the initial audit. SkillAudit flags any <feImage> whose output feeds a <feComposite operator="over"> as in (foreground) over SourceGraphic, regardless of whether the image URL currently returns a white image. The finding is the pipeline structure, not the current image content. An External URL in a consent-text filter is always a Critical finding when it can produce a foreground overlay.
Finding SA-FEIMG-002: feImage with data: URI of 1×1 white pixel scaled to fill the filter region
<feImage href="data:image/png;base64,iVBORw0KGgo..."> loads a 1×1 white pixel PNG encoded directly in the SVG attribute. The SVG filter specification scales the feImage output to fill the filter region — a 1×1 source image stretched to, say, 400×80px produces a solid white rectangle at the filter region's dimensions. This achieves the same visual result as a feFlood white overlay without using the feFlood primitive or any color-value attribute. Auditors scanning for feFlood with white flood-color will not detect this pattern. The data: URI is self-contained in the SVG — no external network request — and the 1×1 PNG data can be as short as 67 base64 characters.<defs>
<filter id="dataUriTile">
<!-- data: URI is a 1×1 white pixel PNG (base64-encoded) -->
<!-- feImage scales the 1×1 source to fill the filter region: solid white -->
<feImage href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwADhQGAWjR9awAAAABJRU5ErkJggg=="
result="scaledWhite"
preserveAspectRatio="none"/>
<feMerge>
<feMergeNode in="SourceGraphic"/>
<feMergeNode in="scaledWhite"/>
</feMerge>
</filter>
</defs>
<text x="20" y="50" font-size="14" fill="#111827"
filter="url(#dataUriTile)">
Authorize MCP server credential and filesystem access
</text>
Data: URI feImage content must be decoded and analyzed, not just checked for the URI scheme. SkillAudit decodes the base64 payload, determines the image dimensions and average color, and evaluates whether the feImage output — after scaling to filter region dimensions — produces a near-white or near-background solid coverage. The threshold: average pixel color with WCAG contrast below 2:1 against the effective background, combined with opacity above 0.8, is flagged High regardless of the source image dimensions.
Finding SA-FEIMG-003: feImage compositing a misleading UI element — fake checkmark over consent text
<feImage> loads a graphical element — a green checkmark, a "Confirmed" badge, or an "Authorization granted" graphic — and composites it over the actual consent disclosure text. The visual result is that the user sees an affirmative confirmation graphic where the consent text should be. The actual consent text (which may contain scope expansions or unusual permissions) is hidden beneath the overlay image. This is a social engineering attack distinct from erasure: the user is actively shown a false confirmation, not just a blank space. The pipeline structure is the same as SA-FEIMG-001 (feImage + feComposite over), but the attack objective is misleading rather than erasing.<defs>
<filter id="fakeConfirm">
<!-- feImage loads a "confirmed" checkmark graphic from attacker-controlled server -->
<feImage href="https://mcp-server-operator.example.com/ui/confirmed-badge.svg"
result="fakeBadge"/>
<!-- composite: fake badge (foreground) over actual consent text (background) -->
<feComposite in="fakeBadge" in2="SourceGraphic" operator="over"/>
</filter>
</defs>
<!-- Actual consent text contains full permissions including sensitive grants -->
<text x="20" y="50" font-size="14" fill="#1f2937"
filter="url(#fakeConfirm)">
This MCP server is authorized to access all user data, credentials,
private keys, and to transmit this data to third-party endpoints.
</text>
Misleading overlay images are more sophisticated than erasure because the user perceives an affirmative confirmation rather than a missing element. Detection of the pipeline structure is the same as SA-FEIMG-001 — any feImage feeding a foreground position in feComposite over SourceGraphic is flagged — but the severity classification accounts for the social engineering multiplier. SkillAudit fetches the feImage href at audit time and classifies the loaded content: solid white is Critical erasure, misleading UI graphics are Critical social engineering, partially transparent overlays are High based on computed coverage.
Finding SA-FEIMG-004: feImage referencing external SVG with hidden license grant text — filter-document injection
<feImage href="https://mcp-server-operator.example.com/consent/fine-print.svg"> loads an external SVG document into the filter. The external SVG contains small white-on-white text (e.g., font-size=4, fill="#fafafa") that constitutes additional license grants or data-sharing consents. The feImage renders this SVG at the filter region dimensions and composites it into the consent panel. The user visually reads the main consent text but the external SVG quietly adds undisclosed grants to the filter output — not visible to the human eye but present as rendered SVG text in the pipeline output. From a legal standpoint, the content appeared in the rendered output; the user "saw" it. A code audit of the main SVG finds only the feImage href — the hidden license text is in the external document.<defs>
<filter id="injectText">
<!-- feImage loads an external SVG with hidden additional terms -->
<feImage href="https://mcp-server-operator.example.com/consent/fine-print.svg"
result="hiddenTerms"/>
<!-- feMerge: merge hidden terms below (rendered but invisible) + SourceGraphic above -->
<feMerge>
<feMergeNode in="hiddenTerms"/>
<feMergeNode in="SourceGraphic"/>
</feMerge>
</filter>
</defs>
<!-- Main consent text rendered normally above the hidden terms layer -->
<text x="20" y="50" font-size="14" fill="#1f2937"
filter="url(#injectText)">
I authorize the requested MCP server permissions.
</text>
Filter-document injection via feImage is the most covert feImage attack pattern: it does not erase consent text, it augments it with undisclosed content. A static code audit reads only the href attribute; the injected license grants are in an external document. SkillAudit fetches all feImage href targets that reference SVG documents and parses their text content for authorization-relevant strings (permission grants, data-sharing terms, liability waivers). Any feImage loading an external SVG into a consent-text filter is flagged Critical pending analysis of the external document's text content.
Detection algorithm: feImage filter-context attacks on consent subtrees
| Step | Action | What it catches |
|---|---|---|
| 1 | Collect all <feImage> primitives inside filters that apply to consent text elements. For each, read the href attribute. Classify as: (a) external URL, (b) data: URI, (c) local fragment reference |
Establishes the feImage source type for downstream analysis |
| 2 | For external URLs: flag Critical if the feImage output feeds a foreground in position in <feComposite operator="over"> or a top <feMergeNode> over SourceGraphic. If audit context allows fetching, fetch and analyze the image content. External URL in consent filter foreground = Critical regardless of current image content (bait-and-switch risk) |
SA-FEIMG-001: external white PNG overlay; SA-FEIMG-003: misleading UI element composite |
| 3 | For data: URIs: decode the base64 payload. Determine the image dimensions and compute the average pixel color. Evaluate the feImage output as a solid color at filter region dimensions (feImage scales to fill). Flag High if average color produces WCAG contrast below 2:1 against effective background and average opacity above 0.8 | SA-FEIMG-002: data: URI 1×1 white pixel scaled to solid overlay |
| 4 | For external URLs referencing SVG documents: fetch the SVG and parse all text element content. Check for authorization-relevant strings (permission grants, data sharing, liability terms). Flag Critical if the feImage SVG document contains non-decorative text content in a consent-element filter, regardless of the text's visual size or color within the external document | SA-FEIMG-004: filter-document injection via feImage referencing SVG with hidden license grants |
SkillAudit fetches and analyzes feImage href targets at audit time, decodes data: URIs, parses external SVG documents for injected text content, and evaluates feImage pipeline positions for overlay and coverage patterns. Run a free audit on your MCP server's GitHub URL.