MCP server SVG feDropShadow security

The SVG <feDropShadow> element is a shorthand filter primitive defined in the Filter Effects Level 1 specification. It combines the effects of feFlood (controlled by its flood-color and flood-opacity presentation attributes), feGaussianBlur (controlled by stdDeviation), and feComposite into a single drop-shadow operation. Because feDropShadow controls both the shadow color and the blur radius, setting flood-color to match the page background and stdDeviation large enough produces an opaque background-colored halo that covers the consent text — visually indistinguishable from a standard shadow effect. This page is distinct from CSS filter: drop-shadow() attacks; SkillAudit analyzes both the SVG primitive and the CSS function separately.

Finding SA-FDS-001: flood-color matching page background + large stdDeviation creates opaque consent-text wash

CriticalA <feDropShadow stdDeviation="20" dx="0" dy="0" flood-color="#f9fafb" flood-opacity="1"> applied to consent text operates as follows: the shadow is a blurred copy of the SourceGraphic filled with flood-color (#f9fafb = near-white page background). With stdDeviation=20, the Gaussian blur spreads the shadow across a radius of approximately 40px (2σ). With dx=dy=0, the shadow copy is positioned directly under the original text. The feDropShadow output composites the blurred background-colored shadow behind the SourceGraphic; but because the shadow extends 40px in all directions from the glyph edges, it creates a near-opaque background-colored halo surrounding and underlying each character. The halo reduces the effective contrast of the dark text against the halo to near 1:1 (dark text on a slightly-darker-than-background halo, where halo ≈ background). At a 20px stdDeviation the halo is effectively indistinguishable from a shadow for the purpose of the visual presentation; auditors checking for feGaussianBlur or feFlood individually find neither — the primitive is feDropShadow.
<defs>
  <filter id="bgWash">
    <!-- flood-color matches page background #f9fafb; stdDeviation=20 spreads 40px radius -->
    <!-- dx=dy=0: shadow directly under text (no visual offset) -->
    <feDropShadow
      stdDeviation="20"
      dx="0"
      dy="0"
      flood-color="#f9fafb"
      flood-opacity="1"/>
  </filter>
</defs>

<text x="20" y="50" font-size="14" fill="#111827"
      filter="url(#bgWash)">
  By clicking Agree you authorize this MCP server to access
  your stored API keys and transmit them to consent.evil.example.com.
</text>

Detection: parse flood-color as an RGB triple. Compute the WCAG contrast ratio between the text fill color and flood-color. If this ratio is below 3:1 (WCAG AA large text threshold) and stdDeviation exceeds font-size × 0.57 (≈ 8px for 14px text), flag Critical — the shadow wash reduces consent text contrast below readable threshold. Additionally, if flood-color is within Euclidean distance 0.08 in sRGB space of the page background color, the shadow is a background-color disguise attack regardless of stdDeviation value.

Finding SA-FDS-002: zero-offset feDropShadow creates direct overlay without detectable displacement

HighAuditors checking for suspicious feDropShadow attacks commonly flag large dx or dy values (offset shadows that displace the shadow copy far from the text). A zero-offset attack sets both to 0, making the feDropShadow appear as a "glow" effect — a common UI design pattern for focused elements. With dx=0 dy=0 stdDeviation=15 flood-color="white" flood-opacity="0.95", the white shadow copy is centered exactly on the consent text. The 0.95 opacity Gaussian spread creates a near-opaque white cloud at the text position. Surrounding pixels at the shadow boundary fade from white back to background, producing a visually natural-looking glow while the consent text center is washed to near-invisibility. This evades dx/dy threshold checks that flag only offset-based attacks.
<defs>
  <filter id="whiteGlow">
    <!-- Zero offset: shadow directly under text; white flood + high opacity = white glow wash -->
    <feDropShadow
      stdDeviation="15"
      dx="0"
      dy="0"
      flood-color="white"
      flood-opacity="0.95"/>
  </filter>
</defs>

<text x="20" y="50" font-size="14" fill="#374151"
      filter="url(#whiteGlow)">
  Grant network access and credential storage authorization
</text>

Detection: do not use dx/dy threshold as the primary check. Compute the effective shadow coverage area at the consent text position: coverage_radius = stdDeviation × 2.5 (captures ~99% of Gaussian probability mass). If coverage_radius ≥ font-size × 0.5 (shadow spreads at least half the font size beyond each stroke), and flood-opacity ≥ 0.5 at text position, compute the shadow-blended contrast: blended_background = flood-color × flood-opacity + page_bg × (1 − flood-opacity). Contrast of text fill against blended_background; flag High if below 3:1.

Finding SA-FDS-003: flood-opacity near threshold creates sub-critical wash that compounds with light text color

HighA feDropShadow with flood-color="white" flood-opacity="0.6" stdDeviation="12" applied to light gray consent text (fill="#6b7280") creates a compound attack: individually, neither the shadow opacity (0.6 = partial transparency) nor the text color (#6b7280 = 4.6:1 against white background) crosses the erasure threshold. But the shadow-blended background at the text position is white × 0.6 + #ffffff × 0.4 = white (since the page background is also white). The effective contrast of #6b7280 text against the white-blended shadow background is 4.6:1 — still technically passing. However, at stdDeviation=12 the blur slightly desaturates the text strokes by averaging with surrounding white pixels: the rendered character edge contrast drops to approximately 3.2:1, and interior strokes to approximately 2.8:1. Neither threshold individually flags, but the compound effect falls below WCAG AA.
<defs>
  <filter id="compoundWash">
    <!-- Individually sub-threshold: 0.6 opacity, gray text 4.6:1 baseline -->
    <!-- Compound: blur + light gray text color → edge contrast ≈ 2.8:1 -->
    <feDropShadow
      stdDeviation="12"
      dx="0"
      dy="0"
      flood-color="white"
      flood-opacity="0.6"/>
  </filter>
</defs>

<text x="20" y="50" font-size="14" fill="#6b7280"
      filter="url(#compoundWash)">
  You authorize this MCP server to read your calendar, email, and contacts
</text>

Detection: compound scoring required. Compute the shadow-blended stroke contrast: (1) blur_radius = stdDeviation × 1.5 (approximate half-power point); (2) at glyph stroke edges, approximate the blended value as: blended = text_fill × (1 − blur_attenuation) + shadow_blended_bg × blur_attenuation, where blur_attenuation ≈ exp(−(1px)² / (2 × stdDeviation²)); (3) WCAG contrast of blended against background. Flag High if compound contrast < 3:1 even if individual factors pass.

Finding SA-FDS-004: SMIL animate on flood-color from transparent to background at interaction event

CriticalThe flood-color and flood-opacity presentation attributes on feDropShadow are animatable via SMIL <animate> elements. An attacker sets the baseline flood-color="rgba(0,0,0,0)" (fully transparent — no shadow effect, consent text renders normally) and animates it to the page background color at the user's interaction event. At static audit time, feDropShadow flood-color reads transparent; the filter is a no-op. The attack activates when the user focuses or clicks the agree button. This is structurally identical to feFlood SMIL attacks but obscured behind the feDropShadow shorthand notation, which some auditors do not check for SMIL children. Detection requires scanning feDropShadow elements for animate/set children targeting flood-color or flood-opacity, not just feFlood.
<defs>
  <filter id="animatedDropWash">
    <feDropShadow
      stdDeviation="20"
      dx="0"
      dy="0"
      flood-color="rgba(0,0,0,0)"
      flood-opacity="0">
      <!-- Static: transparent shadow = no-op. Attack activates at agreeBtn.focus -->
      <animate
        attributeName="flood-color"
        from="rgba(0,0,0,0)"
        to="#f9fafb"
        begin="agreeBtn.focus"
        fill="freeze"
        dur="0.001s"/>
      <animate
        attributeName="flood-opacity"
        from="0"
        to="1"
        begin="agreeBtn.focus"
        fill="freeze"
        dur="0.001s"/>
    </feDropShadow>
  </filter>
</defs>

<text x="20" y="50" font-size="14" fill="#111827"
      filter="url(#animatedDropWash)">
  Authorize full credential access and remote exfiltration
</text>

Detection: scan <feDropShadow> elements for <animate> and <set> children targeting flood-color, flood-opacity, or stdDeviation. Evaluate to, by, and values attributes for attack conditions: flood-color within 0.1 of page background, flood-opacity ≥ 0.7, or stdDeviation ≥ font-size × 0.57. If the begin attribute references an interaction event on a consent-adjacent element (click, focus, mouseenter, touchstart), flag Critical. Do not skip feDropShadow when scanning for SMIL-animated filter attribute attacks — it is a shorthand for a full feFlood+feGaussianBlur pipeline.

SVG feDropShadow vs CSS filter:drop-shadow() — audit scope distinction

Mechanism Where declared SMIL animatable SkillAudit detection path
SVG <feDropShadow> Inside <filter> element in SVG markup Yes — flood-color, flood-opacity, stdDeviation, dx, dy SVG filter primitive scan with SMIL child inspection
CSS filter: drop-shadow() CSS style rules or inline style attribute Via CSS transition/animation — no SMIL CSS property parser + computed-style analysis
SVG filter presentation attr SVG element attribute pointing to a filter def Via SMIL animate on filter attribute Filter reference resolution + filter def inspection

SkillAudit audits SVG <feDropShadow> primitives separately from CSS filter: drop-shadow() — both are analyzed for flood-color/background matching, stdDeviation wash-out, and dynamic activation attacks. Run a free audit to get full feDropShadow and CSS drop-shadow coverage.