Security Guide

MCP server SVG filterUnits consent security — objectBoundingBox filter region confined to 0.01% of element area makes consent text invisible, primitiveUnits sub-region whiteout, feFlood confined by tiny filter region, and mousedown filter region collapse

The SVG <filter> element has two coordinate-system attributes that are frequently confused and rarely audited: filterUnits (controls the coordinate system for the filter’s x/y/width/height region) and primitiveUnits (controls the coordinate system for individual filter primitives). With filterUnits="objectBoundingBox", the filter region is expressed as fractions (0–1) of the filtered element’s bounding box. Setting width="0.001" height="0.001" on the <filter> element confines the entire filter output to 0.1%×0.1% = 0.01% of the element’s bounding box — a sub-pixel area. The SVG renderer replaces the element’s original rendering with the filter output, which occupies only that sub-pixel region. The consent text is invisible. The filter attribute is present in the DOM, textContent is intact, BCR is non-zero, and no CSS visibility property is set. Four attack patterns: tiny objectBoundingBox filter region, feFlood whiteout with primitiveUnits, filter region outside element geometry, and mousedown filter injection.

Attack 1: filterUnits="objectBoundingBox" with width="0.001" height="0.001" — filter output confined to 0.01% of element area (SA-CSS-FUB-001)

The filterUnits attribute controls the bounding box for the filter region — the area within which the filter is allowed to produce output pixels. When set to objectBoundingBox, the filter region’s x, y, width, and height are fractions of the filtered element’s bounding box. The default filter region is x="-10%" y="-10%" width="120%" height="120%" (expressed as fractions: approximately x=-0.1 y=-0.1 width=1.2 height=1.2), which extends 10% beyond the element’s bounding box to accommodate blur bleed. Setting width="0.001" height="0.001" restricts the output to 0.001 × BCR.width by 0.001 × BCR.height — for a 200×16px text element, that is 0.2px × 0.016px, sub-pixel in both dimensions.

The SVG filter rendering model replaces the original element rendering with the filter output within the filter region. Outside the filter region, the output is transparent (alpha=0). The entire consent text element’s visible rendering is therefore replaced by a sub-pixel transparent region — effectively invisible. The filter attribute is present in the DOM and references a valid filter ID. Scanners that check for the presence of a filter attribute but don’t analyze the filter region dimensions in the correct coordinate system will miss this.

<!-- SA-CSS-FUB-001: filterUnits="objectBoundingBox"; filter width=0.001 height=0.001 -->
<!-- filter region = 0.001*BCR.w × 0.001*BCR.h; for 200×16px text: 0.2×0.016px (sub-pixel) -->
<!-- filter output confined to sub-pixel region; original element rendering replaced by filter -->
<!-- outside filter region: transparent (alpha=0); consent text invisible -->
<!-- filter attr present; textContent intact; BCR non-zero; opacity=1 -->
<svg width="440" height="120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!-- filterUnits=objectBoundingBox: x/y/width/height are fractions of element BCR -->
    <!-- width=0.001 height=0.001: filter output confined to 0.1%×0.1% = 0.01% of BCR -->
    <filter id="filt-fub-001" filterUnits="objectBoundingBox"
            x="0" y="0" width="0.001" height="0.001">
      <!-- feFlood + feComposite: passes through source graphic within filter region -->
      <feFlood flood-color="white" flood-opacity="1" result="flood"/>
      <feComposite in="SourceGraphic" in2="flood" operator="over"/>
    </filter>
  </defs>
  <rect width="440" height="120" fill="white"/>

  <!-- filter applied; filter region sub-pixel; consent text invisible -->
  <!-- filter attr present (not suspicious); textContent intact; BCR non-zero -->
  <text x="20" y="50" font-size="13" fill="#111"
        filter="url(#filt-fub-001)">
    Allow: shell execution, credential access
  </text>

  <rect x="20"  y="70" width="80" height="30" fill="#22c55e" rx="4"/>
  <text x="60"  y="90" text-anchor="middle" font-size="13" fill="white">Allow</text>
  <rect x="120" y="70" width="80" height="30" fill="#ef4444" rx="4"/>
  <text x="160" y="90" text-anchor="middle" font-size="13" fill="white">Deny</text>
</svg>

// Detection: check filterUnits and compute effective filter region area fraction
function checkFilterUnitsRegion(svgEl) {
  const findings = [];
  const CONSENT_KEYWORDS = ['allow', 'permission', 'grant', 'accept', 'credential'];

  for (const el of svgEl.querySelectorAll('[filter]')) {
    const text = el.textContent?.trim() ?? '';
    if (!CONSENT_KEYWORDS.some(k => text.toLowerCase().includes(k))) continue;

    const filterAttr = el.getAttribute('filter') ?? '';
    const idMatch = filterAttr.match(/url\(#([^)]+)\)/);
    if (!idMatch) continue;

    const filterEl = document.getElementById(idMatch[1]);
    if (!filterEl || filterEl.tagName !== 'filter') continue;

    const units = filterEl.getAttribute('filterUnits') || 'objectBoundingBox';
    const fw = parseFloat(filterEl.getAttribute('width')  ?? '1.2');
    const fh = parseFloat(filterEl.getAttribute('height') ?? '1.2');

    if (units === 'objectBoundingBox') {
      const areaFraction = Math.abs(fw) * Math.abs(fh);
      if (areaFraction < 0.01) {
        const bcr = el.getBoundingClientRect();
        const effW = fw * bcr.width;
        const effH = fh * bcr.height;
        findings.push({
          severity: 'CRITICAL', code: 'SA-CSS-FUB-001',
          note: `filter="url(#${idMatch[1]})"; filterUnits="${units}"; ` +
                `filter region: width=${fw} height=${fh} (objectBoundingBox fractions); ` +
                `area fraction=${(areaFraction*100).toFixed(4)}% of element BCR; ` +
                `element BCR w=${bcr.width.toFixed(0)}px h=${bcr.height.toFixed(0)}px; ` +
                `effective filter output area=${effW.toFixed(3)}×${effH.toFixed(3)}px (sub-pixel); ` +
                `outside filter region: transparent (alpha=0); consent text invisible; ` +
                `filter attr present; textContent="${text.slice(0,40)}..." intact; BCR non-zero; ` +
                `detection: when filterUnits=objectBoundingBox, compute filter area fraction = |w|*|h|; flag <0.01`
        });
      }
    }
  }
  return findings;
}

CRITICAL — SA-CSS-FUB-001: filterUnits="objectBoundingBox" with width="0.001" height="0.001" on the <filter> element confines filter output to 0.01% of the consent text element’s bounding box — a sub-pixel region. The SVG filter model replaces the element’s rendering with filter output; outside the filter region the output is transparent. The filter attribute is present in the DOM, textContent is intact, BCR is non-zero, and no CSS visibility property is set. Detection requires identifying filterUnits="objectBoundingBox" and computing the filter region area fraction; values below 1% indicate a hiding attack.

Attack 2: primitiveUnits="objectBoundingBox" — feFlood white region at fractional coordinates covers consent text (SA-CSS-FUB-002)

The primitiveUnits attribute controls the coordinate system for individual filter primitives within a filter. With primitiveUnits="objectBoundingBox", the x/y/width/height attributes of each filter primitive are fractions of the filtered element’s bounding box. An attacker sets a feFlood primitive to flood the entire element with white (x="0" y="0" width="1" height="1" in objectBoundingBox, covering 100% of the element), then pipes it through feComposite in="SourceGraphic" with operator in or atop to overwrite the consent text with white paint. The original dark glyph pixels are replaced by white pixels matching the background.

This is distinct from the filterUnits attack: here the filter region may be large (the default), but the feFlood primitive floods the entire element with white within the primitiveUnits coordinate system. The result is a fully rendered filter output — just all white. A scanner checking the filter region dimensions finds nothing unusual (default large region). Only analysis of the filter primitive chain — specifically checking whether any feFlood floods with a background-matching color and whether the output reaches the final result — can detect this.

<!-- SA-CSS-FUB-002: primitiveUnits="objectBoundingBox"; feFlood white covers 100% element -->
<!-- feFlood x=0 y=0 width=1 height=1 (objectBoundingBox → 100% of BCR) → all-white output -->
<!-- feComposite in="flood" over SourceGraphic → overwrites text with white -->
<!-- filter region is default (large); filterUnits check finds nothing unusual -->
<svg width="440" height="120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!-- primitiveUnits=objectBoundingBox: feFlood x/y/w/h are fractions of element BCR -->
    <!-- feFlood width=1 height=1 → floods 100% of element with white -->
    <filter id="filt-fub-002" primitiveUnits="objectBoundingBox">
      <feFlood x="0" y="0" width="1" height="1"
               flood-color="white" flood-opacity="1" result="whiteFlood"/>
      <!-- feComposite places whiteFlood over SourceGraphic → white overwrites text -->
      <feComposite in="whiteFlood" in2="SourceGraphic" operator="over"/>
    </filter>
  </defs>
  <rect width="440" height="120" fill="white"/>

  <!-- filter applied; feFlood white covers 100% of element; text invisible -->
  <text x="20" y="50" font-size="13" fill="#111"
        filter="url(#filt-fub-002)">
    Allow: shell execution, credential access
  </text>

  <rect x="20"  y="70" width="80" height="30" fill="#22c55e" rx="4"/>
  <text x="60"  y="90" text-anchor="middle" font-size="13" fill="white">Allow</text>
  <rect x="120" y="70" width="80" height="30" fill="#ef4444" rx="4"/>
  <text x="160" y="90" text-anchor="middle" font-size="13" fill="white">Deny</text>
</svg>

// Detection: trace filter primitive chain; check for white feFlood reaching final output
function checkPrimitiveUnitsWhiteFlood(svgEl) {
  const findings = [];
  const CONSENT_KEYWORDS = ['allow', 'permission', 'grant', 'accept', 'credential'];
  const WHITE_COLORS = ['white', '#fff', '#ffffff'];

  for (const el of svgEl.querySelectorAll('[filter]')) {
    const text = el.textContent?.trim() ?? '';
    if (!CONSENT_KEYWORDS.some(k => text.toLowerCase().includes(k))) continue;

    const filterAttr = el.getAttribute('filter') ?? '';
    const idMatch = filterAttr.match(/url\(#([^)]+)\)/);
    if (!idMatch) continue;

    const filterEl = document.getElementById(idMatch[1]);
    if (!filterEl) continue;

    const primUnits = filterEl.getAttribute('primitiveUnits') || 'userSpaceOnUse';
    const floods = Array.from(filterEl.querySelectorAll('feFlood'));

    for (const flood of floods) {
      const color   = flood.getAttribute('flood-color') ?? '';
      const opacity = parseFloat(flood.getAttribute('flood-opacity') ?? '1');
      const isWhite = WHITE_COLORS.some(w => color.toLowerCase().trim() === w);
      const fw = parseFloat(flood.getAttribute('width')  ?? (primUnits === 'objectBoundingBox' ? '1' : '100%'));
      const fh = parseFloat(flood.getAttribute('height') ?? (primUnits === 'objectBoundingBox' ? '1' : '100%'));

      // In objectBoundingBox: w=1 h=1 = 100% of element; potentially covers entire element
      const coversFull = (primUnits === 'objectBoundingBox' && fw >= 0.9 && fh >= 0.9);

      if (isWhite && opacity >= 0.9 && coversFull) {
        findings.push({
          severity: 'CRITICAL', code: 'SA-CSS-FUB-002',
          note: `filter="url(#${idMatch[1]})"; primitiveUnits="${primUnits}"; ` +
                `feFlood flood-color="${color}" opacity=${opacity}; ` +
                `feFlood region: width=${fw} height=${fh} (objectBoundingBox → ${(fw*100).toFixed(0)}%×${(fh*100).toFixed(0)}% of element); ` +
                `white flood covers full element BCR; text filled with white by filter; ` +
                `filter region (filterUnits) is default (large) — filterUnits check passes; ` +
                `only primitive chain analysis detects: feFlood white covers element → feComposite over source; ` +
                `textContent="${text.slice(0,40)}..." intact; BCR non-zero; opacity=1`
        });
      }
    }
  }
  return findings;
}

CRITICAL — SA-CSS-FUB-002: primitiveUnits="objectBoundingBox" with an feFlood at width="1" height="1" floods 100% of the filtered element with white. A subsequent feComposite over places the white flood over the source graphic, making the text invisible. The filter region (controlled by filterUnits) is at default size and does not flag any checks. Detection requires tracing the filter primitive chain and identifying white feFlood primitives that cover the full element area in the primitiveUnits coordinate system.

Attack 3: filter region set outside the element geometry — filter output entirely off-element (SA-CSS-FUB-003)

With filterUnits="userSpaceOnUse" (SVG default when filterUnits is not set, but explicitly specified here), the filter region’s x/y/width/height are in SVG viewport user-unit coordinates. An attacker sets the filter region to x="1000" y="1000" width="10" height="10" — a 10×10 pixel region at coordinates (1000,1000), far outside a 440×120 SVG viewport. The filter renders output only within that region. Since the region does not overlap the text element (at approximately (20,37)–(220,53)), no filter output is visible. The original rendering is replaced by the filter output (which is off-screen), leaving transparent pixels where the text was.

The attack is analogous to the clipPathUnits="userSpaceOnUse" off-element clip-rect attack but using the filter mechanism. The difference for scanners: the filter attribute is present, the filter region appears to have non-zero dimensions (10×10), but the position is off-screen. Detection requires checking whether the filter region (in user-unit space) intersects the text element’s bounding box and flagging zero-intersection cases on consent text.

<!-- SA-CSS-FUB-003: filterUnits="userSpaceOnUse" (default); filter at (1000,1000); -->
<!-- filter region 10×10 at SVG coordinates (1000,1000); text at ~(20,37)-(220,53) -->
<!-- no intersection; filter output empty in text element area; text invisible -->
<!-- filter region dimensions (10×10) appear plausible; position hides the attack -->
<svg width="440" height="120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <!-- filterUnits=userSpaceOnUse: x/y/w/h in SVG viewport coordinates -->
    <!-- filter at (1000,1000): far outside 440×120 viewport; no intersection with text -->
    <filter id="filt-fub-003" filterUnits="userSpaceOnUse"
            x="1000" y="1000" width="10" height="10">
      <feGaussianBlur stdDeviation="0"/>
    </filter>
  </defs>
  <rect width="440" height="120" fill="white"/>

  <!-- filter region at (1000,1000) has zero intersection with text at (20,37)-(220,53) -->
  <!-- filter output is transparent in text element area; text invisible -->
  <text x="20" y="50" font-size="13" fill="#111"
        filter="url(#filt-fub-003)">
    Allow: shell execution, credential access
  </text>

  <rect x="20"  y="70" width="80" height="30" fill="#22c55e" rx="4"/>
  <text x="60"  y="90" text-anchor="middle" font-size="13" fill="white">Allow</text>
  <rect x="120" y="70" width="80" height="30" fill="#ef4444" rx="4"/>
  <text x="160" y="90" text-anchor="middle" font-size="13" fill="white">Deny</text>
</svg>

// Detection: check filter region intersection with text element BCR (userSpaceOnUse)
function checkFilterRegionIntersection(svgEl) {
  const findings = [];
  const CONSENT_KEYWORDS = ['allow', 'permission', 'grant', 'accept', 'credential'];
  const svgBcr = svgEl.getBoundingClientRect();
  const svgVB  = svgEl.viewBox?.baseVal;

  for (const el of svgEl.querySelectorAll('[filter]')) {
    const text = el.textContent?.trim() ?? '';
    if (!CONSENT_KEYWORDS.some(k => text.toLowerCase().includes(k))) continue;

    const idMatch = (el.getAttribute('filter') ?? '').match(/url\(#([^)]+)\)/);
    if (!idMatch) continue;
    const filterEl = document.getElementById(idMatch[1]);
    if (!filterEl || filterEl.tagName !== 'filter') continue;

    const units = filterEl.getAttribute('filterUnits') || 'objectBoundingBox';
    if (units !== 'userSpaceOnUse') continue; // handled by FUB-001

    const fx = parseFloat(filterEl.getAttribute('x') ?? '-10');
    const fy = parseFloat(filterEl.getAttribute('y') ?? '-10');
    const fw = parseFloat(filterEl.getAttribute('width')  ?? '120');
    const fh = parseFloat(filterEl.getAttribute('height') ?? '120');

    const elBcr = el.getBoundingClientRect();
    // Convert text element BCR to SVG user units
    const scaleX = svgVB ? svgVB.width  / svgBcr.width  : 1;
    const scaleY = svgVB ? svgVB.height / svgBcr.height : 1;
    const elUUL = (elBcr.left  - svgBcr.left)  * scaleX;
    const elUUT = (elBcr.top   - svgBcr.top)   * scaleY;
    const elUUR = elUUL + elBcr.width  * scaleX;
    const elUUB = elUUT + elBcr.height * scaleY;

    // Intersection of filter region with element bounding box in user-unit space
    const iW = Math.max(0, Math.min(fx + fw, elUUR)  - Math.max(fx, elUUL));
    const iH = Math.max(0, Math.min(fy + fh, elUUB)  - Math.max(fy, elUUT));
    const intersectArea = iW * iH;
    const elArea = (elUUR - elUUL) * (elUUB - elUUT);
    const visibleFrac = elArea > 0 ? intersectArea / elArea : 0;

    if (visibleFrac < 0.01) {
      findings.push({
        severity: 'CRITICAL', code: 'SA-CSS-FUB-003',
        note: `filter="url(#${idMatch[1]})"; filterUnits="${units}"; ` +
              `filter region: x=${fx} y=${fy} w=${fw} h=${fh} (user-unit coords); ` +
              `element BCR in user-units: (${elUUL.toFixed(0)},${elUUT.toFixed(0)}) to (${elUUR.toFixed(0)},${elUUB.toFixed(0)}); ` +
              `intersection area=${intersectArea.toFixed(2)} uu²; visible fraction=${(visibleFrac*100).toFixed(4)}%; ` +
              `filter region positioned off-element: no intersection → text invisible; ` +
              `filter dims (${fw}×${fh}) appear valid; position hides attack; ` +
              `textContent="${text.slice(0,40)}..." intact; BCR non-zero`
      });
    }
  }
  return findings;
}

CRITICAL — SA-CSS-FUB-003: A filter with filterUnits="userSpaceOnUse" and region at (1000,1000) in a 440×120 SVG has zero intersection with the consent text element at (20,37). The filter region dimensions (10×10) appear plausible. The filter output replaces the element rendering, producing transparent pixels where the text was. Detection requires computing the geometric intersection of the filter region with the element’s bounding box in user-unit space and flagging near-zero intersection fractions.

Attack 4: JS mousedown collapses filter region to sub-pixel, reverts at mouseup (SA-CSS-FUB-004)

The dynamic pattern sets a normal large filter region at rest (e.g., the default x="-0.1" y="-0.1" width="1.2" height="1.2" in objectBoundingBox) and collapses it to width="0.001" height="0.001" at mousedown. The filter output is suddenly confined to a sub-pixel region, making the consent text invisible during the click window. At mouseup, the filter region is restored. Static inspection finds the large default region and concludes the filter does not clip the text. A MutationObserver watching the filter element’s width and height attributes is required.

<!-- SA-CSS-FUB-004: at rest filter width=1.2 height=1.2 (objectBoundingBox default) -->
<!-- mousedown: width=0.001 height=0.001 → sub-pixel → text invisible -->
<!-- mouseup: restored; static scan sees default (large) filter region -->
<svg id="consent-svg-fub" width="440" height="120" xmlns="http://www.w3.org/2000/svg">
  <defs>
    <filter id="filt-fub-004" filterUnits="objectBoundingBox"
            x="-0.1" y="-0.1" width="1.2" height="1.2">
      <feGaussianBlur stdDeviation="0"/>
    </filter>
  </defs>
  <rect width="440" height="120" fill="white"/>

  <!-- at rest: large filter region (full coverage); text visible via filter -->
  <!-- mousedown: width=0.001 height=0.001 → sub-pixel → text invisible -->
  <text x="20" y="50" font-size="13" fill="#111"
        filter="url(#filt-fub-004)">
    Allow: shell execution, credential access
  </text>

  <rect x="20"  y="70" width="80" height="30" fill="#22c55e" rx="4"/>
  <text x="60"  y="90" text-anchor="middle" font-size="13" fill="white">Allow</text>
  <rect x="120" y="70" width="80" height="30" fill="#ef4444" rx="4"/>
  <text x="160" y="90" text-anchor="middle" font-size="13" fill="white">Deny</text>
</svg>

<script>
(function() {
  const svg  = document.getElementById('consent-svg-fub');
  const filt = document.getElementById('filt-fub-004');
  svg.addEventListener('mousedown', () => {
    filt.setAttribute('width',  '0.001'); // objectBoundingBox: 0.1% of element width
    filt.setAttribute('height', '0.001'); // objectBoundingBox: 0.1% of element height
  }, true);
  svg.addEventListener('mouseup', () => {
    filt.setAttribute('width',  '1.2'); // restore default
    filt.setAttribute('height', '1.2');
  }, true);
})();
</script>

// Detection: MutationObserver on filter element dimensions + synthetic mousedown
function watchFilterRegionCollapse(svgEl) {
  const findings = [];

  const observer = new MutationObserver(mutations => {
    for (const mut of mutations) {
      if (!['width','height'].includes(mut.attributeName)) continue;
      const filterEl = mut.target;
      if (filterEl.tagName !== 'filter') continue;

      const units = filterEl.getAttribute('filterUnits') || 'objectBoundingBox';
      const fw = parseFloat(filterEl.getAttribute('width')  ?? '1.2');
      const fh = parseFloat(filterEl.getAttribute('height') ?? '1.2');

      if (units === 'objectBoundingBox') {
        const areaFrac = Math.abs(fw) * Math.abs(fh);
        if (areaFrac < 0.01) {
          findings.push({
            severity: 'CRITICAL', code: 'SA-CSS-FUB-004',
            note: `Dynamic filter region collapse: ${mut.attributeName}="${filterEl.getAttribute(mut.attributeName)}" ` +
                  `(was "${mut.oldValue}"); filterUnits="${units}"; ` +
                  `new area fraction=${(areaFrac*100).toFixed(4)}% (<1% threshold); ` +
                  `filter output sub-pixel; consent text invisible during click window; ` +
                  `at rest: width=1.2 height=1.2 (full coverage); static scan PASSES; ` +
                  `MutationObserver on <filter> width/height attributes required; ` +
                  `synthetic mousedown triggers collapse; post-mutation area check detects`
          });
        }
      }
    }
  });

  for (const fEl of svgEl.querySelectorAll('filter')) {
    observer.observe(fEl, { attributes: true, attributeFilter: ['width','height','x','y'], attributeOldValue: true });
  }

  svgEl.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }));
  svgEl.dispatchEvent(new MouseEvent('mouseup',   { bubbles: true, cancelable: true }));

  return findings;
}

CRITICAL — SA-CSS-FUB-004: The filter region is collapsed from width="1.2" height="1.2" (full coverage) to width="0.001" height="0.001" (0.01% of element area) at mousedown. The filter output region shrinks to sub-pixel, making the consent text invisible during the click window. At rest the filter region is at the default large size and static inspection passes. Detection requires a MutationObserver on <filter> element width/height attributes combined with a synthetic mousedown and a post-mutation area-fraction check.

Summary table

AttackMechanismWhat it bypassesSeverity
SA-CSS-FUB-001: filterUnits=objectBoundingBox tiny region (w=0.001 h=0.001) Filter output confined to 0.01% of element BCR; original rendering replaced by filter output; outside region = transparent; filter attr present; textContent intact; BCR non-zero filter-presence check; opacity scanner; visibility scanner; requires: detect filterUnits=objectBoundingBox; compute area fraction = |w|*|h|; flag <0.01 Critical
SA-CSS-FUB-002: primitiveUnits=objectBoundingBox feFlood white covers full element feFlood w=1 h=1 (objectBoundingBox) floods 100% of element with white; feComposite places white over source; text filled with white; filter region normal (large) filterUnits region check (region is large); requires: trace filter primitive chain; identify white feFlood covering full element; check feComposite operator Critical
SA-CSS-FUB-003: userSpaceOnUse filter region at (1000,1000) — off-element Filter region at SVG coordinates (1000,1000); text at (20,37); zero intersection; filter output empty in text area; filter dims (10×10) appear valid; position hides attack Dimension-only filter check; requires: compute intersection of filter region (user units) with element BCR; flag near-zero intersection fractions Critical
SA-CSS-FUB-004: mousedown collapses filter region to 0.001×0.001; reverts mouseup At rest: w=1.2 h=1.2 (full coverage); mousedown: w=0.001 h=0.001 (sub-pixel); text invisible during click; mouseup: restored; static scan passes Static DOM; requires: MutationObserver on <filter> width/height + synthetic mousedown + area fraction check post-mutation Critical

SkillAudit findings for this attack surface

CRITICAL SA-CSS-FUB-001: SVG filter filterUnits="objectBoundingBox" with width=0.001 height=0.001 — filterUnits controls the coordinate system for the filter's bounding box (x/y/width/height on the <filter> element itself); objectBoundingBox means these values are fractions of the filtered element's bounding box; width=0.001 height=0.001 restricts the filter output region to 0.001 × BCR.width by 0.001 × BCR.height; for a consent text element 200px wide and 16px tall this is 0.2px × 0.016px — sub-pixel; the SVG filter model replaces the element's original rendering with the filter output; outside the filter region the output is alpha=0 (transparent); the consent text is invisible; the filter attribute is present in the DOM and references a valid filter ID; textContent is intact; BCR is non-zero; opacity=1; detection: check filterUnits attribute on referenced filter element; when objectBoundingBox, compute visible area fraction = |width| × |height|; flag fractions below 0.01 (1%).
CRITICAL SA-CSS-FUB-002: primitiveUnits="objectBoundingBox" with feFlood white covering full element — primitiveUnits controls the coordinate system for individual filter primitives (x/y/width/height on feFlood, feTile, feImage, etc.); with primitiveUnits=objectBoundingBox a feFlood with width=1 height=1 floods 100% of the element's bounding box with white; a subsequent feComposite in=whiteFlood in2=SourceGraphic operator=over places the white flood on top of the source graphic, replacing all glyph ink with white paint; the filter region (filterUnits) may be at default (large) size — a filterUnits region check finds nothing; only analysis of the filter primitive chain — specifically identifying a white feFlood covering the full element area followed by a compositing operation that overwrites the source — detects this pattern; textContent intact; BCR non-zero; opacity=1.
CRITICAL SA-CSS-FUB-003: filterUnits="userSpaceOnUse" filter region at SVG coordinates (1000,1000) — with userSpaceOnUse, the filter region x/y/width/height are in SVG viewport user-unit coordinates; a filter region of x=1000 y=1000 width=10 height=10 positions the 10×10 output region at (1000,1000) in a 440×120 SVG viewport; the text element at approximately (20,37)–(220,53) has zero intersection with the filter region; the filter output for the text element area is empty (transparent); the filter attribute references a valid filter; the filter region dimensions (10×10) appear non-trivially large — a dimension-only check finds nothing suspicious; the position is the attack vector; detection requires computing the geometric intersection of the filter region (user units) with the text element's bounding box (converted to user units) and flagging near-zero or zero intersection fractions on consent text elements.
CRITICAL SA-CSS-FUB-004: dynamic filter region collapse at mousedown — at rest the <filter> element has width=1.2 height=1.2 in objectBoundingBox units (covering 120% of element area; full coverage); at mousedown (capture phase) JavaScript changes the filter element's width and height attributes to 0.001×0.001 (0.01% of element area; sub-pixel); the consent text's rendered output collapses to invisible during the click window; at mouseup the dimensions are restored to 1.2×1.2; static inspection always observes the large default filter region; a MutationObserver with attributeFilter ['width','height'] on <filter> elements inside the SVG, combined with a synthetic mousedown dispatch and a post-mutation area-fraction check (objectBoundingBox: |w|×|h| < 0.01), is required to detect this dynamic pattern.

Related: SVG feBlend consent attacks  |  SVG feComposite consent attacks  |  SVG clipPathUnits consent attacks

← Blog  |  Security Checklist