MCP server SVG feColorMatrix luminanceToAlpha consent security
Four SA-CSS-LTA consent attack patterns using feColorMatrix type="luminanceToAlpha" — mapping pixel luminance to alpha and zeroing RGB to make dark consent text near-transparent — with feComposite selective erasure and JS mousedown type injection.
The feColorMatrix SVG filter primitive applies a matrix transformation to RGBA channels. When type="luminanceToAlpha", it uses a fixed formula derived from the CIE luminance coefficients: output_A = 0.2126 × R + 0.7152 × G + 0.0722 × B, and sets output_R = output_G = output_B = 0. The output is a grayscale alpha map of the input's luminance. This is distinct from the general type="matrix" path — it cannot be replicated by a 5×4 matrix (because it involves the source alpha), and is processed via a separate code path in browser implementations.
Text color dependency: Unlike feConvolveMatrix zero-kernel attacks (which zero all channels regardless of input), luminanceToAlpha attacks are selective by luminance. Dark text has near-zero luminance → near-zero output alpha → near-transparent. Bright text has high luminance → high output alpha → opaque (but RGB=0, so opaque black). Attack selection must match the target text luminance profile.
SA-CSS-LTA-001: dark consent text → near-transparent (luminance-dependent)
A dark-colored consent text element (e.g., color: #333333, sRGB linearized R=0.133, G=0.133, B=0.133) has luminance = 0.2126×0.133 + 0.7152×0.133 + 0.0722×0.133 = 0.133 × (0.2126+0.7152+0.0722) = 0.133 × 1.0 = 0.133. The luminanceToAlpha transform sets output alpha to 0.133. This is 87% transparent. On a white background, dark text with 87% transparency appears as very faint pale text — contrast ratio well below WCAG 4.5:1.
For very dark text like #1a1a1a (luminance ≈ 0.016), output alpha ≈ 0.016, which is 98% transparent. The text is effectively invisible. This is why luminanceToAlpha is particularly effective against dark-text-on-light-background consent dialogs — the most common consent UI style.
<filter id="lta1"> <feColorMatrix type="luminanceToAlpha"/> </filter> <!-- Input: dark text #333 (luminance=0.133) → output alpha=0.133, RGB=(0,0,0) → 87% transparent --> <!-- getComputedStyle.color still returns "rgb(51,51,51)" unchanged -->
SA-CSS-LTA-002: feComposite operator="out" selective erasure
The luminanceToAlpha result can be used as a mask input for feComposite. With operator="out", the formula is out(A, B) = A × (1 - alpha_B). Using the luminanceToAlpha result as in2 (B), pixels where the original source had high opacity become erased: the consent text pixels (source alpha=1) produce luminance_alpha × (1-1) = 0; the background (source alpha=0 outside the element) produces 0 × anything = 0. The result is that text pixels are zeroed while background pixels (outside the element) remain at zero anyway.
This is a more targeted erasure that operates on alpha-compositing relationships rather than a simple channel replacement. It evades checks that look for all-zero output because the compositing logic is two-step (luminanceToAlpha then feComposite), and each step individually appears plausible.
<filter id="lta2"> <feColorMatrix type="luminanceToAlpha" result="lum_alpha"/> <feComposite in="lum_alpha" in2="SourceGraphic" operator="out"/> </filter> <!-- lum_alpha: alpha = luminance, RGB = 0. feComposite out: pixels where SourceGraphic is opaque → erased -->
SA-CSS-LTA-003: white-on-dark consent themes (non-evasion case)
For a consent dialog with white text on a dark background (color: #ffffff, luminance=1.0), luminanceToAlpha sets output alpha=1.0 and RGB=(0,0,0). The result is opaque black. On a dark background, opaque black may be more visible than the white text — making the consent text appear dark gray/black rather than invisible. Luminance-based attackers must therefore select their target based on the consent text color profile. This finding exists to document the non-evasion case and prevent false interpretation of luminanceToAlpha as a universal attack. Against dark consent text it is a high-severity attack; against white consent text it may actually increase visibility.
SA-CSS-LTA-004: JS mousedown type injection (matrix → luminanceToAlpha)
The feColorMatrix initially uses type="matrix" with an identity values (5×4 matrix with 1s on the diagonal, 0s elsewhere). The identity matrix passes all channels through unchanged. The consent text renders normally. On mousedown, the script changes type to "luminanceToAlpha". For dark consent text, output alpha immediately drops to the luminance value (~0.1), making the text near-transparent. The mousedown event fires before the visual update is committed to the screen, so the user cannot see the change before their click registers.
consentElement.addEventListener("mousedown", () => {
const fcm = document.getElementById("consentFilter")
.querySelector("feColorMatrix");
fcm.setAttribute("type", "luminanceToAlpha");
// No values attribute change needed — luminanceToAlpha uses its own fixed formula
});
Detection requirement: type="luminanceToAlpha" does not involve a values attribute. Scanners that only check feColorMatrix values for suspicious patterns will miss this attack entirely. The type attribute must be explicitly checked. Flag type="luminanceToAlpha" on any feColorMatrix in a consent ancestor filter; evaluate whether the consent text luminance is below 0.5 (dark text → likely transparent output).
Attack summary
| ID | type | Target text luminance | Effect | Severity |
|---|---|---|---|---|
| SA-CSS-LTA-001 | luminanceToAlpha | Dark (<0.2) | Near-transparent alpha; text invisible on any background | Critical |
| SA-CSS-LTA-002 | luminanceToAlpha + feComposite out | Any | Selective erasure of foreground pixels via alpha compositing | High |
| SA-CSS-LTA-003 | luminanceToAlpha | Bright (≥0.8) | Output = opaque black; not an evasion for white-on-dark | Medium (FP risk) |
| SA-CSS-LTA-004 | matrix→luminanceToAlpha (mousedown) | Dark (<0.2) | Near-transparent at click time; initial state normal | Critical |
Defences
- Flag
type="luminanceToAlpha"on feColorMatrix in consent filters: There is no legitimate reason to apply luminanceToAlpha to consent text elements. Flag unconditionally and evaluate the consent text luminance to determine attack severity. - Compute consent text luminance: Resolve the
getComputedStyle.colorof the consent element, convert to linear light, and apply the luminance formula. If luminance < 0.2, the attack produces near-transparent output (HIGH severity). If luminance > 0.8, the attack produces opaque black (may increase visibility on dark backgrounds — document as lower severity). - Check feComposite chain: If
luminanceToAlpharesult is used as in2 for afeComposite operator="out"oroperator="in", evaluate the compositing formula. These combinations can produce selective erasure that neither step flags in isolation. - MutationObserver on feColorMatrix
type: SA-CSS-LTA-004 changes only thetypeattribute. Addtypeto the MutationObserver attribute list alongsidevaluesfor all feColorMatrix elements in consent ancestor filter chains. A change from any type toluminanceToAlphais always suspicious on a consent element.
SkillAudit findings for this attack surface
feColorMatrix type="luminanceToAlpha" on consent element with dark text (luminance < 0.2) — output alpha ≈ luminance (near-zero); near-transparent; text invisible on any background; getComputedStyle.color unchanged; no alpha-zero check catches this (alpha is not exactly zero).luminanceToAlpha result used as in2 for feComposite operator="out" — selective alpha compositing erases foreground text pixels; two-primitive chain; each primitive individually plausible; evaluation requires following result references through the filter graph.luminanceToAlpha on consent element with bright text (luminance ≥ 0.8) — output alpha ≈ 1 (opaque), RGB = (0,0,0) = opaque black; may increase visibility on dark backgrounds; lower severity; document as false-positive case for white-on-dark consent themes.feColorMatrix type from "matrix" to "luminanceToAlpha" — initial state identity matrix (consent text visible); near-transparent at click time for dark text; MutationObserver on type attribute of all feColorMatrix in consent-ancestor filters required.