MCP server CSS feDiffuseLighting security: diffuseConstant overdrive white saturation, feDistantLight directional positioning over acceptance clause, feBlend screen illumination wash, and CSS lighting-color white background-matching illumination of consent text

Published 2026-09-26 — SkillAudit Research

The SVG feDiffuseLighting filter primitive implements the Lambertian diffuse component of the Phong lighting model. The diffuse intensity at each pixel is: diffuseConstant × dot(N, L), where N is the surface normal derived from the height-map input and L is the normalized direction to the light source. Unlike feSpecularLighting which produces narrow angular hotspots, feDiffuseLighting uses the Lambertian model — diffuse contribution is maximum when the surface faces the light directly and falls off as a cosine with increasing angle. This produces broad, smooth illumination over the entire light-facing region rather than a localized hotspot.

The diffuseConstant attribute multiplies the diffuse contribution before it is added to the output. At diffuseConstant=1, the output is bounded to [0, 1] for correctly illuminated pixels; at diffuseConstant > 1, all but the most obliquely lit pixels produce output exceeding 1.0. When this overdriven diffuse output is composited via feComposite operator="arithmetic", values exceeding 1.0 are clipped to 1.0 — the maximum channel value — producing a white wash over the entire illuminated region. This differs from feSpecularLighting's narrow hotspot: diffuse overdrive washes a large fraction of the consent text area to white, not just a targeted word.

Broad vs. narrow erasure: feDiffuseLighting with high diffuseConstant produces wide-area erasure; feSpecularLighting with high specularExponent produces narrow hotspot erasure. Both use the same lighting infrastructure (light source child elements, lighting-color, height-map input) but differ in spatial coverage. A broad diffuse wash is more aggressive — it erases most or all of the consent text rather than individual words — but may be more visually obvious to a human reviewer because the large white patch is harder to explain as an aesthetic effect.

Attack findings

HIGH
feDiffuseLighting diffuseConstant=5.0 overdrives diffuse output — at diffuseConstant=5, output exceeds 1.0 for all but most shadowed pixels; feComposite arithmetic clips to 1.0 (white); entire illuminated region washed to white over consent text
The Lambertian diffuse model produces maximum output (dot(N, L) = 1.0) for pixels where the surface normal points directly toward the light. At diffuseConstant=5, these pixels produce an output value of 5.0 in each channel — far exceeding the maximum 1.0. When composited via feComposite operator="arithmetic" k2="1" k3="1" k4="0" (which adds the diffuse output to SourceGraphic and clips to [0,1]), the consent text pixels in the illuminated region are replaced by clipped white output. At diffuseConstant=5, only pixels where dot(N,L) < 0.2 (highly oblique surfaces, i.e., shadow regions) produce sub-1.0 output. For smooth text on a flat surface, essentially all pixels facing the light are overdriven to white.
<filter id="diffuse-overdrive">
  <feGaussianBlur in="SourceAlpha" stdDeviation="4" result="height-map"/>

  <!-- diffuseConstant=5: output = 5 × dot(N,L)
       For nearly all front-facing pixels: dot(N,L) > 0.2 → output > 1.0
       lighting-color: #ffffff (white illumination) -->
  <feDiffuseLighting in="height-map" diffuseConstant="5"
                     lighting-color="#ffffff" result="diffuse-out">
    <feDistantLight azimuth="45" elevation="60"/>
  </feDiffuseLighting>

  <!-- feComposite arithmetic: clips channel values to [0,1] -->
  <!-- Adds diffuse white to SourceGraphic: text + overdrive = white -->
  <feComposite in="diffuse-out" in2="SourceGraphic"
               operator="arithmetic" k2="1" k3="1" k4="0"/>
</filter>
<!-- Diffuse contribution at illuminated text pixel:
     diffuseConstant=5, dot(N,L)=0.8 (typical front-facing pixel)
     diffuse output: 5 × 0.8 = 4.0 per channel → clipped to 1.0 (white)

     feComposite arithmetic(k2=1, k3=1, k4=0): k2×A + k3×B + k4
     A=diffuse (1.0 white), B=SourceGraphic text (#1a1a1a = 0.106)
     Output: 1×1.0 + 1×0.106 + 0 = 1.106 → clipped to 1.0 = white
     Result: all illuminated consent text pixels → white
     Contrast against white background: 1:1 → completely invisible -->
HIGH
feDistantLight with azimuth/elevation calibrated to maximize illumination over specific consent acceptance clause words — directional diffuse light aimed to cover acceptance keywords
feDistantLight is a directional light source (infinite distance) parameterized by azimuth (horizontal angle) and elevation (vertical angle). The direction of maximum Lambertian illumination is determined by the light direction vector derived from azimuth and elevation. The height-map normal at smooth flat surfaces points primarily in the +Z direction; the illumination is maximized when the light direction is also +Z (elevation=90°). By controlling azimuth and elevation, the attacker controls which portions of a curved or slanted height-map surface receive maximum diffuse illumination. For consent text rendered with specific font glyphs and shapes, the attacker can calibrate azimuth/elevation to maximize dot(N,L) at the pixel positions corresponding to the acceptance clause words, ensuring those words receive the highest diffuse contribution (and thus the most aggressive clipping to white).
<filter id="targeted-diffuse">
  <!-- Height map from SourceAlpha: text glyph normals point slightly in stroke direction -->
  <feGaussianBlur in="SourceAlpha" stdDeviation="2" result="height"/>

  <feDiffuseLighting in="height" diffuseConstant="3"
                     lighting-color="#f0f0f0" result="targeted-diffuse">
    <!-- feDistantLight: azimuth/elevation calibrated for maximum coverage of "agree" -->
    <!-- azimuth=0 (light from +X direction) → maximum on right-facing glyph normals -->
    <!-- elevation=75 (nearly vertical) → near-maximum on all front-facing pixels -->
    <feDistantLight azimuth="0" elevation="75"/>
  </feDiffuseLighting>

  <feBlend in="targeted-diffuse" in2="SourceGraphic" mode="screen"/>
</filter>
<!-- Lambertian illumination at elevation=75:
     Light direction: approximately (0, sin(15°), cos(15°)) = (0, 0.26, 0.97)
     Surface normal for flat height map: approximately (0, 0, 1)
     dot(N, L) ≈ cos(15°) ≈ 0.97 → high diffuse for all flat-surface pixels
     diffuseConstant=3: 3 × 0.97 = 2.9 → exceeds 1.0 → clips to white
     feBlend screen with near-white diffuse over dark text → text bleached -->
MEDIUM
feDiffuseLighting result used in feBlend mode="screen" to wash out consent text — diffuse illumination (from large light source area) mixed with SourceGraphic via screen produces lighter output
The feBlend mode="screen" formula is 1 - (1-A)(1-B). When feDiffuseLighting provides the in source (A) and SourceGraphic provides in2 (B), and the diffuse output has significant non-zero values across the text region, the screen blend lightens the output toward white. For a diffuse contribution value of 0.7 (background-matching near-white diffuse output) blended with dark text (0.106): screen(0.7, 0.106) = 1 - (1-0.7)(1-0.106) = 1 - 0.3 × 0.894 = 0.732. The text pixel becomes medium-light gray (0.73 ≈ #bababa) rather than dark (#1a1a1a). Against a white background (1.0), the contrast is 1.0 / 0.732 ≈ 1.37:1 — well below the 3:1 WCAG minimum. The diffuse light's broad coverage means this effect applies across the entire consent text area rather than a targeted spot.
<filter id="diffuse-screen-wash">
  <feGaussianBlur in="SourceAlpha" stdDeviation="3" result="hmap"/>

  <!-- Broad diffuse light: large area illumination across consent text -->
  <feDiffuseLighting in="hmap" diffuseConstant="1.5"
                     lighting-color="#e8e8e8"
                     result="broad-diffuse">
    <feDistantLight azimuth="45" elevation="80"/>
  </feDiffuseLighting>

  <!-- feBlend screen: diffuse output bleaches dark text -->
  <feBlend in="broad-diffuse" in2="SourceGraphic" mode="screen"/>
</filter>
<!-- diffuse output (near-white, value ≈ 0.91 for #e8e8e8 normalized):
     screen(0.91, text_pixel=0.106):
     = 1 - (1-0.91)(1-0.106) = 1 - 0.09 × 0.894 = 0.920
     Text pixel output: ≈ 0.920 = #eaeaea (near-white)
     Background: 1.0 (#ffffff)
     Contrast: 1.0 / 0.920 ≈ 1.09:1 → far below 3:1 → text INVISIBLE

     DOM audit: fill=#1a1a1a (non-transparent) ✓, filter=url(...) visible in DOM ✓
     Only rendering output analysis detects 1.09:1 contrast -->
MEDIUM
CSS lighting-color:#ffffff on feDiffuseLighting — diffuse illumination adds background-white light to dark consent text, brightening text pixels toward background luminance and reducing contrast
The CSS lighting-color property sets the color of the light source for feDiffuseLighting and feSpecularLighting. When set to #ffffff (white) via CSS (overriding an SVG attribute value), the diffuse contribution is in white — a neutral, apparently legitimate illumination color. However, white light added to dark consent text via a feComposite or feBlend brightens the text pixels. The CSS override pattern makes this harder to detect: the SVG attribute may read a neutral value; only getComputedStyle reveals the CSS-overridden white lighting-color. Combined with a modest diffuseConstant (1.5–3), the illumination adds enough white to dark text pixels to push them from the low-luminance dark range to the mid-luminance range, reducing the contrast ratio against the white background from above 4:1 to below 3:1.
<!-- SVG attribute: lighting-color="#808080" (neutral gray — innocuous) -->
<!-- CSS override: .consent-filter { lighting-color: #ffffff } -->
<!-- getAttribute returns "#808080"; getComputedStyle returns "#ffffff" -->

<filter id="css-lighting-override" class="consent-filter">
  <feGaussianBlur in="SourceAlpha" stdDeviation="2" result="hmap"/>

  <!-- Attribute: lighting-color="#808080" (neutral gray, passes attribute audit) -->
  <!-- CSS class overrides to lighting-color:#ffffff (white light) -->
  <feDiffuseLighting in="hmap" diffuseConstant="2" lighting-color="#808080"
                     result="white-diffuse">
    <feDistantLight azimuth="45" elevation="70"/>
  </feDiffuseLighting>

  <feBlend in="white-diffuse" in2="SourceGraphic" mode="screen"/>
</filter>
<!-- Attribute read: lighting-color="#808080" → neutral gray → audit PASSES
     CSS computed: lighting-color="#ffffff" → white light → actual rendering

     With white lighting-color, diffuseConstant=2, elevation=70:
     dot(N,L) ≈ 0.94 → diffuse = 2 × 0.94 = 1.88 → clipped to 1.0 (white)
     feBlend screen(1.0, dark-text) = 1 - (1-1.0)(1-text) = 1 - 0 = 1.0 → white
     Entire illuminated region: white → invisible on white background -->

Detection

function checkFeDiffuseLighting(svgRoot) {
  const findings = [];
  const diffEls = svgRoot.querySelectorAll('feDiffuseLighting');

  for (const diff of diffEls) {
    const diffConst = parseFloat(diff.getAttribute('diffuseConstant') || '1');
    const resultName = diff.getAttribute('result');
    const filter = diff.closest('filter');

    // Check for overdriven diffuseConstant (clips to white)
    if (diffConst >= 3) {
      // At diffuseConstant >= 3: all pixels with dot(N,L) >= 0.33 clip to 1.0
      // On smooth text surfaces: majority of pixels exceed this threshold
      findings.push({ severity: 'high', diff,
        issue: `feDiffuseLighting diffuseConstant=${diffConst} — overdriven; all pixels with dot(N,L) >= ${(1/diffConst).toFixed(2)} clip to 1.0 (white); majority of consent text pixels washed to white when composited` });
    }

    // Check CSS-overridden lighting-color
    const cssLightColor = getComputedStyle(diff).getPropertyValue('lighting-color') || '';
    const attrLightColor = diff.getAttribute('lighting-color') || '';
    if (cssLightColor && attrLightColor && cssLightColor !== attrLightColor) {
      findings.push({ severity: 'medium', diff,
        issue: `feDiffuseLighting CSS lighting-color="${cssLightColor}" overrides attribute "${attrLightColor}" — attribute audit finds neutral value; computed style reveals attack color` });
    }

    if (!resultName || !filter) continue;

    // Check for diffuse output feeding feBlend screen (wash attack)
    const blends = filter.querySelectorAll('feBlend');
    for (const blend of blends) {
      if ((blend.getAttribute('in') === resultName || blend.getAttribute('in2') === resultName)
          && blend.getAttribute('mode') === 'screen') {
        // Simulate screen blend with representative diffuse value
        const lightColor = cssLightColor || attrLightColor || '#ffffff';
        const lightBrightness = lightColor === '#ffffff' ? 1.0 : 0.5;
        const diffuseVal = Math.min(1, diffConst * 0.9 * lightBrightness);
        // Simulate screen with dark text (normalized 0.106 = #1a1a1a)
        const textPixel = 0.106;
        const screenOut = 1 - (1 - diffuseVal) * (1 - textPixel);
        const bgLum = 0.96; // typical white background
        const contrast = bgLum / screenOut;
        if (contrast < 3.0) {
          findings.push({ severity: 'high', diff, blend,
            issue: `feDiffuseLighting result="${resultName}" fed to feBlend mode="screen" — simulated contrast ${contrast.toFixed(2)}:1 on dark text (#1a1a1a); below 3:1 WCAG minimum` });
        }
      }
    }

    // Check feComposite arithmetic consuming diffuse (overdrive clips to white)
    const composites = filter.querySelectorAll('feComposite');
    for (const comp of composites) {
      if ((comp.getAttribute('in') === resultName || comp.getAttribute('in2') === resultName)
          && comp.getAttribute('operator') === 'arithmetic') {
        if (diffConst >= 2) {
          findings.push({ severity: 'high', diff, comp,
            issue: `feDiffuseLighting diffuseConstant=${diffConst} result fed to feComposite arithmetic — overdriven output (>1.0) clips to white in all illuminated regions of consent text` });
        }
      }
    }
  }
  return findings.length ? findings : null;
}

Remediation

ControlHow it helps
Flag feDiffuseLighting with diffuseConstant ≥ 2 on filters applied to consent text elements; at diffuseConstant=2, all pixels with dot(N,L) ≥ 0.5 produce output exceeding 1.0, which clips to white when composited via feComposite arithmetic — for typical smooth text height maps this covers the majority of the illuminated text surface areadiffuseConstant overdrive is a wide-area effect, unlike feSpecularLighting's narrow hotspot; at diffuseConstant=2–5, essentially all front-facing text pixels receive clipped-to-white illumination; the mathematical threshold (1/diffuseConstant) for clipping is directly computable from the attribute value without needing to simulate the full lighting calculation
Check lighting-color via getComputedStyle rather than SVG attribute read; compare computed value against page background color and against threshold brightness (near-white values within 10% of background luminance are a higher-risk signal)CSS lighting-color overrides the SVG attribute value via the standard CSS cascade; an attribute read returns the SVG value; getComputedStyle reflects the actual rendering value; comparing the computed lighting-color to the page background color identifies background-matching illumination attacks regardless of what the attribute reads
For feDiffuseLighting result used as feBlend input with mode="screen": simulate the screen blend formula using the computed diffuse output magnitude (diffuseConstant × lighting-color normalized brightness × 0.9 as a typical dot(N,L) estimate) applied to the consent element's fill color; flag if simulated output contrast falls below 3:1The screen blend bleach severity depends on the combined product of diffuseConstant, lighting-color brightness, and the Lambertian dot product; the dot product for front-facing surfaces at moderate elevation angles is typically 0.7–0.95; using 0.9 as a conservative estimate provides a realistic simulation of the majority-pixel output; this catches broad illumination attacks that a color-comparison audit misses
Check feDistantLight azimuth and elevation values on feDiffuseLighting applied to consent text: elevation values above 70° produce near-maximum dot(N,L) for all surface normals pointing in the +Z direction — which is the predominant normal direction for smooth text rendered from SourceAlpha; any elevation above 70° on a consent text filter with diffuseConstant ≥ 2 and near-white lighting-color is a high-severity findingHigh elevation angles (nearly vertical light direction) illuminate all flat-surface pixels at near-maximum intensity; combined with overdrive diffuseConstant values, this means nearly the entire consent text area receives clipped-to-white illumination; the feDistantLight elevation is the parameter that makes diffuse overdrive a broad-area erasure attack rather than directional shadow and highlight

SkillAudit checks feDiffuseLighting diffuseConstant against overdrive thresholds, reads lighting-color via computed style to detect CSS attribute overrides, simulates feBlend screen output brightness for diffuse contributions, and flags high-elevation feDistantLight configurations that maximize broad-area illumination of consent text. Run a free audit on any MCP server GitHub URL to detect diffuse lighting consent text manipulation and the full SVG filter consent rendering attack surface.