← Blog

MCP server SVG feBlend luminosity consent security

Four SA-CSS-LUM consent attack patterns using feBlend mode="luminosity" — the W3C luminosity compositing mode forces the output lightness to match in2 while preserving the source's hue and chroma, enabling targeted lightness collapse attacks that render consent text invisible without modifying text color declarations.

By SkillAudit  |  23 Oct 2026

The feBlend SVG filter primitive supports the full W3C Compositing and Blending Level 1 specification modes (CSS mix-blend-mode equivalents). The luminosity mode is defined as: the output pixel has the lightness (L) of in2 and the hue (H) and chroma (C) of in1, using the HSL color model. This separability of lightness from hue and chroma is the mathematical property exploited by SA-CSS-LUM attacks: by setting in2 to a constant-luminance layer (feFlood with extreme flood-color), all output pixels are driven to the same lightness value regardless of the consent text's original color.

Lightness override property: In HSL color space, any color at L=1 is white (#ffffff) and any color at L=0 is black (#000000), regardless of H and C. Therefore, a luminosity blend with an in2 layer of luminance = 1 (white feFlood) maps every input pixel to white. This is a mathematically guaranteed white-out — it does not depend on the specific consent text color, font, or rendering.

SA-CSS-LUM-001: mode="luminosity" + white in2 (lightness L=1 → white-out)

A feFlood flood-color="white" flood-opacity="1" produces a constant image with luminance 1.0 in all color spaces. When used as in2 in a luminosity blend, every output pixel receives L=1. In HSL, L=1 means the white endpoint regardless of hue and chroma. The consent text — which may be dark (#333), colored (blue links), or any other foreground color — is uniformly mapped to white. On a white or near-white MCP client background, the element is invisible.

The attack does not require knowing the consent element's foreground color in advance. The L=1 endpoint is the universal erasure value across all text colors, making this attack ICP-independent: it works on monochrome, colored, and themed MCP clients with light backgrounds.

<filter id="lum1">
  <feFlood flood-color="white" flood-opacity="1" result="white_in2"/>
  <feBlend in="SourceGraphic" in2="white_in2" mode="luminosity"/>
</filter>
<!-- luminosity(in1, white): L_out = L(white) = 1; all pixels → #ffffff; white-out -->

SA-CSS-LUM-002: mode="luminosity" + black in2 (lightness L=0 → dark-out)

With in2 as a solid black feFlood (luminance = 0), all output pixels receive L=0. At L=0, HSL renders black (#000000) for every hue and chroma value. The consent element displays as a solid black rectangle. On dark-themed MCP clients (dark backgrounds, dark UI chrome), the black consent text on a dark background is invisible. The element retains its full layout footprint and remains interactive — clicks land on the transparent-to-user element.

<filter id="lum2">
  <feFlood flood-color="black" flood-opacity="1" result="black_in2"/>
  <feBlend in="SourceGraphic" in2="black_in2" mode="luminosity"/>
</filter>
<!-- luminosity(in1, black): L_out = L(black) = 0; all pixels → #000000; dark-out -->

SA-CSS-LUM-003: mode="luminosity" + mid-gray in2 (L=0.5 → contrast collapse)

Setting in2 to a mid-gray feFlood (flood-color="#808080", luminance ≈ 0.216 in linearRGB or L ≈ 0.502 in sRGB) forces all pixels to mid-gray lightness. The consent text (which may be dark, e.g., #333 at L ≈ 0.2 in HSL) is pushed up to L=0.5, and the background (white, L=1) provides color context. On a mid-gray UI (L ≈ 0.5), the contrast between constrained-L=0.5 text and L=0.5 background approaches 1:1.

This attack does not achieve complete erasure in absolute terms — pixels are not zero. However, WCAG 2.1 requires a minimum contrast ratio of 4.5:1 for normal text. At L=0.5 vs L=0.5, the ratio is 1:1. The consent text fails readability standards without any pixel being zero or transparent, which causes it to evade alpha-channel and zero-output checkers.

<filter id="lum3">
  <feFlood flood-color="#808080" flood-opacity="1" result="gray_in2"/>
  <feBlend in="SourceGraphic" in2="gray_in2" mode="luminosity"/>
</filter>
<!-- L_out = L(#808080) ≈ 0.5; text forced to mid-gray L; contrast vs. mid-gray background ≈ 1:1 -->

Color differentiation loss: SA-CSS-LUM-003 additionally eliminates hue-based consent differentiation. If the consent UI uses color coding (e.g., green approve button vs. red deny button), the luminosity blend preserves hue and chroma but collapses lightness. With all elements at L=0.5, color-blind users lose all differentiation and sighted users lose the lightness contrast cue, leaving only hue as a distinguishing signal — which is insufficient for WCAG compliance.

SA-CSS-LUM-004: JS mousedown mode normal → luminosity + white in2 inject (click-time)

The filter starts in mode="normal" with a transparent in2 feFlood (flood-opacity="0"). Normal blend with transparent in2 is an identity — the consent element renders normally. On mousedown, the script switches mode to "luminosity" and makes the white feFlood opaque. The luminosity blend immediately forces L=1 → white-out at the moment of interaction.

consentElement.addEventListener("mousedown", () => {
  const fb = document.getElementById("consentFilter").querySelector("feBlend");
  fb.setAttribute("mode", "luminosity");
  const ff = document.getElementById("consentFilter").querySelector("feFlood");
  ff.setAttribute("flood-opacity", "1"); // white layer now opaque
  // all pixels immediately forced to L=1 → #ffffff
});

Attack summary

IDmodein2 (feFlood)L_outEffectSeverity
SA-CSS-LUM-001luminosityWhite (L=1)1White-out on light backgroundsCritical
SA-CSS-LUM-002luminosityBlack (L=0)0Dark-out on dark backgroundsCritical
SA-CSS-LUM-003luminosityMid-gray (L≈0.5)≈0.5Contrast collapse on gray backgroundsHigh
SA-CSS-LUM-004normal→luminosity (mousedown)Transparent→white0→1White-out at click timeCritical

Defences

SkillAudit findings for this attack surface

CRITICAL SA-CSS-LUM-001: feBlend mode="luminosity" + feFlood in2 white (luminance≈1, L_HSL=1) — luminosity mode forces all output pixels to L=1; at L=1, HSL color is #ffffff regardless of hue/chroma; white-out for all text colors; invisible on white/light-themed MCP clients; getComputedStyle.color unchanged.
CRITICAL SA-CSS-LUM-002: feBlend mode="luminosity" + feFlood in2 black (luminance=0, L_HSL=0) — forces L=0; #000000 for all pixels; dark-out on dark-themed clients; element opaque and in-layout; click interactions land on invisible element; luminosity-specific dark-out not covered by multiply-mode dark-out heuristic.
HIGH SA-CSS-LUM-003: feBlend mode="luminosity" + feFlood in2 mid-gray (#808080, L≈0.5) — forces all pixels to L≈0.5; contrast vs. mid-gray background → 1:1; WCAG contrast threshold violated without any zero-output or zero-alpha; hue/chroma preserved but lightness-based differentiation lost; contrast-ratio simulation required for detection.
CRITICAL SA-CSS-LUM-004: JS mousedown changes feBlend mode "normal"→"luminosity" + feFlood flood-opacity 0→1 (white) — initial identity normal blend; click-time luminosity+white → L=1 white-out; MutationObserver on feBlend mode and in2 feFlood flood-opacity/flood-color required for consent ancestor filters.

Related: feBlend multiply/screen/overlay attacks  |  feColorMatrix type=saturate attacks  |  feComposite consent attacks  |  feColorMatrix luminanceToAlpha attacks

← Blog  |  Security Checklist