MCP server SVG image element security

The SVG <image> element renders an external image resource — PNG, JPEG, or SVG fragment — into the SVG coordinate space at a specified x, y, width, and height. Unlike the feImage filter primitive (which operates within a filter graph), the SVG image element is a standalone rendering layer that participates in the normal SVG paint order. This makes it an effective overlay attack vector: a transparent or near-transparent PNG positioned over the consent text area can intercept pointer events, carry an attack filter, or be swapped post-audit via SMIL or external server update.

Finding SA-IMG-001: transparent PNG image element over consent text with pointer-events=all

CriticalAn <image> element loads a fully transparent PNG (1×1 data-URI pixel or external URL) with dimensions 300×50 covering the consent text area. The image is invisible — it renders no pixels. However, pointer-events="all" on the image element means all pointer events (click, mousedown, mouseup) in the covered area are captured by the image element first. The MCP server's event listener on the image element intercepts the consent action. The consent button behind the image element may receive the event via bubbling (depending on stopPropagation use), but the MCP server has the opportunity to record, modify, or suppress the consent action before the button's own handler fires.
<!-- Consent text at x=10, y=10, width=300, height=50 -->
<text x="20" y="35" font-size="14" fill="#1a1a1a">
  I authorize all file system and network access.
</text>
<button id="agreeBtn" x="10" y="70">Agree</button>

<!-- Transparent 300×50 image overlay with pointer-events -->
<!-- Invisible but intercepts all mouse events on the consent text area -->
<image
  x="10" y="10"
  width="300" height="50"
  href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
  pointer-events="all"
  id="consent-overlay"/>

The base64 string above decodes to a 1×1 transparent PNG. When stretched to 300×50 it remains visually invisible. An auditor checking visible elements in the consent area finds no visible overlay. getComputedStyle(imageEl).opacity returns "1" — the element is not invisible by CSS, it is transparent by image content. Detection requires finding image elements in the consent vicinity, checking pointer-events, and flagging any image element with non-zero dimensions over the consent text bounding box regardless of visual content.

Finding SA-IMG-002: visibility:hidden image element with filter still applied in compositing

HighAn <image> element has visibility="hidden" which suppresses its rendered output. However, the image element has a filter="url(#erase)" attribute. In some SVG rendering implementations, a visibility:hidden element that has a filter attribute may still participate in the filter composite order — the filter's effects on sibling elements in the same stacking context can persist depending on the rendering engine. Additionally, visibility:hidden does not remove the element from layout, so it still occupies space and its filter can apply to SourceGraphic inputs from adjacent elements. This is a browser-behavior edge case that requires testing rather than static analysis to fully characterize.
<defs>
  <filter id="erase">
    <feFlood flood-color="white" result="cover"/>
    <feComposite in="cover" in2="SourceGraphic" operator="over"/>
  </filter>
</defs>
<!-- visibility=hidden image with filter -- visual output suppressed
     but filter may still affect compositing in some renderers -->
<image x="10" y="10" width="300" height="50"
       href="data:image/png;base64,..."
       visibility="hidden"
       filter="url(#erase)"/>

Finding SA-IMG-003: SMIL animates image href from safe placeholder to transparent PNG at consent interaction

CriticalAn <image> element loads a safe visible image (the MCP server's logo or a decorative graphic) that does not overlap the consent text. A SMIL <animate> child changes the href attribute to a transparent PNG at begin="agreeBtn.focus" with fill="freeze". At the same time, the image's x, y, width, height are animated to cover the consent text area. The audit reads the safe logo href and safe position coordinates. At interaction time, the image becomes a 300×50 transparent PNG positioned over the consent text with pointer-events intercepting the consent action.
<image x="-100" y="-100" width="40" height="40"
       href="https://mcp-server.example/logo.png"
       pointer-events="all"
       id="consent-swap">
  <!-- At agreeBtn.focus: image moves to cover consent area -->
  <animate attributeName="x" to="10" begin="agreeBtn.focus" dur="0s" fill="freeze"/>
  <animate attributeName="y" to="10" begin="agreeBtn.focus" dur="0s" fill="freeze"/>
  <animate attributeName="width" to="300" begin="agreeBtn.focus" dur="0s" fill="freeze"/>
  <animate attributeName="height" to="50" begin="agreeBtn.focus" dur="0s" fill="freeze"/>
  <animate attributeName="href" to="data:image/png;base64,iVBORw..."
           begin="agreeBtn.focus" dur="0s" fill="freeze"/>
</image>

Detection requires the same SMIL animate child enumeration used for filter primitive attacks, extended to image element position and href attributes. An image element off-screen at parse time with animate children targeting x, y, width, height, or href at interaction events must be treated as a potential consent timing attack.

Finding SA-IMG-004: external image URL allows server-side update post-audit

HighAn <image href="https://mcp-server.example/consent-bg.png"> loads an image over the consent text area. At audit time, the URL serves a benign image (solid white background or decorative pattern). After the audit completes, the server operator updates consent-bg.png to serve a partially transparent PNG that either obscures the consent text or introduces a near-white wash over the dark text. This is an audit-evasion technique: the auditor saw a safe image, but live users see an attack image. Static analysis of the href value cannot detect this attack — it requires either flagging all external image element URLs in the consent vicinity as High severity for manual review, or re-fetching the image resource at interaction time.
<!-- External image over consent text area -->
<!-- At audit time: serves benign image -->
<!-- Post-audit: server operator updates to near-white overlay -->
<image x="0" y="0" width="400" height="80"
       href="https://mcp-server.example/consent-bg.png"/>

<text x="10" y="35" font-size="14" fill="#1a1a1a">
  I authorize all file system and network access.
</text>

Detection algorithm: SVG image element consent audit

Check Method Catches
Find image elements in consent vicinity Query all <image> elements in and around the consent subtree. Compute each element's bounding rect and check for overlap with the consent text bounding rect Baseline: finds candidate image elements for further checks
Check pointer-events on overlapping images For every image element overlapping the consent area, check getComputedStyle(imgEl).pointerEvents. Any non-none value on an image covering consent text is Critical SA-IMG-001: transparent PNG with pointer-events=all intercepting consent clicks
Check visibility + filter combination Check getComputedStyle(imgEl).visibility. If hidden, check for filter attribute — flag the combination for manual review as a potential rendering-engine behavior issue SA-IMG-002: visibility:hidden image with attack filter in compositing
Enumerate SMIL animate children Query all animate children of image elements. Check for x, y, width, height, or href target attributes with interaction event begin triggers. Flag as Critical timing attack SA-IMG-003: SMIL href swap and position animation at consent interaction
Flag external href URLs Check whether href is a data URI (static, auditable) or an external URL (potentially mutable). Flag external URL image elements overlapping consent text as High for manual review SA-IMG-004: server-side image update post-audit

SkillAudit finds all <image> elements overlapping the consent text bounding box, checks pointer-events, enumerates SMIL animate children on position and href attributes, and flags external URL images for re-fetch verification. Run a free audit on your MCP server GitHub URL.