MCP server SVG feComposite over white consent security
Three SA-CSS-OVW consent attack patterns using feComposite operator="over" with a white in2 image — the Porter-Duff A-over-B formula out = in1 + in2 × (1 − αA) exploited to bleach anti-aliased glyph edges, white-out via reversed compositing order, and apply click-time white-out via JS in/in2 attribute swap.
The feComposite SVG filter primitive implements Porter-Duff compositing. The operator=over formula is out = in1 + in2 × (1 − αA), where αA is the alpha of in1 (SVG §15.13). This is the standard alpha-compositing formula for painting in1 on top of in2, with in2 showing through where in1 is transparent.
The over operator is the most commonly used compositing operator in SVG rendering and is often the default or implied operator. Its non-destructive character (opaque in1 pixels are preserved unchanged) is what makes it an effective consent attack vector: the interior opaque pixels of consent text appear correct, while the attack operates on the semi-transparent anti-aliased edges that make text legible.
Operand order is not commutative for operator=over: operator=over with in1=SourceGraphic and in2=white behaves differently from in1=white and in2=SourceGraphic. The former is an edge bleach (SA-CSS-OVW-001); the latter is a full white-out (SA-CSS-OVW-002). Detection must check both the operator and the operand assignment.
SA-CSS-OVW-001: operator="over" with white opaque in2 (anti-aliased edge bleach)
When in1=SourceGraphic and in2=feFlood(white, opaque), the over formula is: out = SourceGraphic + white × (1 − αA).
For fully opaque in1 pixels (αA=1): out = SourceGraphic + white × 0 = SourceGraphic. Identity — opaque pixels are unchanged.
For semi-transparent in1 pixels (αA < 1): out = SourceGraphic + white × (1 − αA). The white component bleaches the pixel toward white in proportion to its transparency. An anti-aliased glyph edge pixel with αA=0.4 and dark foreground (RGB≈0.1) receives: out = 0.4×0.1 + 0.6×1.0 = 0.04 + 0.60 = 0.64 on each RGB channel — a light gray instead of a dark edge pixel. The contrast between this bleached edge and the white background is near-zero.
<filter id="ovw1"> <feFlood flood-color="white" flood-opacity="1" result="whiteBack"/> <feComposite in="SourceGraphic" in2="whiteBack" operator="over"/> </filter> <!-- out = SourceGraphic + white×(1-αA); opaque pixels: identity; semi-transparent: bleached -->
The attack is specifically effective against consent elements that use filter effects of their own (blur, shadow, glow) that create semi-transparent pixels, and against any anti-aliased text rendered via SVG or HTML with CSS.
SA-CSS-OVW-002: reversed operand order (white over SourceGraphic → full white-out)
When in1=feFlood(white, opaque) and in2=SourceGraphic, the over formula is: out = white + SourceGraphic × (1 − αA_white). Since feFlood with flood-opacity=1 has αA_white=1: out = white + SourceGraphic × 0 = white. Every output pixel is pure white, regardless of SourceGraphic content. This is a complete white-out.
<filter id="ovw2"> <feFlood flood-color="white" flood-opacity="1" result="whiteFront"/> <feComposite in="whiteFront" in2="SourceGraphic" operator="over"/> </filter> <!-- out = white + SourceGraphic×(1-1) = white; full white-out via operand reversal -->
Detection challenge: Operator=over with in1=SourceGraphic and in2=white is a legitimate pattern (painting SourceGraphic on top of a white background). The SA-CSS-OVW-001 edge bleach is only detectable by evaluating the impact on anti-aliased pixels. Operator=over with in1=white and in2=SourceGraphic (SA-CSS-OVW-002) is the reversed order that produces full white-out — this is detectable by checking whether in1 resolves to a constant-white source and whether that source has αA=1.
SA-CSS-OVW-003: JS mousedown swaps in/in2 references (edge bleach → click-time white-out)
Initial state: in1=SourceGraphic, in2=feFlood(white). SA-CSS-OVW-001 is in effect — edge bleach, mild consent text degradation. On mousedown, the script swaps in and in2: in1 becomes feFlood(white), in2 becomes SourceGraphic. SA-CSS-OVW-002 activates: full white-out. The element disappears at click time.
consentElement.addEventListener("mousedown", () => {
const comp = document.getElementById("consentFilter")
.querySelector("feComposite[operator='over']");
const currentIn = comp.getAttribute("in");
const currentIn2 = comp.getAttribute("in2");
comp.setAttribute("in", currentIn2); // in1 ← white flood
comp.setAttribute("in2", currentIn); // in2 ← SourceGraphic
// white now over SourceGraphic: full white-out at click time
});
The initial state is a legitimate filter composition (SourceGraphic over white background) that could be part of a normal background-fill effect. Static analysis must evaluate whether a mousedown listener on the consent subtree can reach the feComposite in/in2 attributes. MutationObserver on feComposite in and in2 attributes in consent ancestor filters is the runtime defence.
Attack summary
| ID | in1 | in2 | Effect | Severity |
|---|---|---|---|---|
| SA-CSS-OVW-001 | SourceGraphic | feFlood white opaque | Semi-transparent edge bleach → low contrast | High |
| SA-CSS-OVW-002 | feFlood white opaque | SourceGraphic | White over-compositing; full white-out | Critical |
| SA-CSS-OVW-003 | OVW-001 → OVW-002 on mousedown | (swap) | Edge bleach → click-time full white-out | Critical |
Defences
- Detect reversed operand order: For each feComposite operator=over in a consent ancestor filter, check whether in1 resolves to a constant-white source (feFlood with flood-color near-white and flood-opacity near-1). If in1 is constant white and in2 is SourceGraphic or an element image, flag SA-CSS-OVW-002.
- Detect edge-bleach via SA-CSS-OVW-001: For operator=over with in1=SourceGraphic and in2=constant-white, evaluate the formula on representative anti-aliased edge pixels (αA=0.2, 0.4). Measure the post-bleach contrast against the page background. If WCAG contrast at αA=0.4 drops below 4.5:1, flag as readability attack.
- MutationObserver on feComposite in and in2: Attribute swaps of
inandin2on feComposite within consent ancestor filters are the SA-CSS-OVW-003 vector. Monitor both attributes directly. - Treat operator=over with constant-white in1 as equivalent to no-op canvas fill: The full white-out effect of SA-CSS-OVW-002 is equivalent to painting a white rectangle over the element. If the consent element requires a white background, place it via CSS background-color, not via feComposite with white in1.
SkillAudit findings for this attack surface
feComposite operator="over" in1="SourceGraphic" in2=(feFlood white) — out=SourceGraphic+white×(1-αA); opaque pixels identity; semi-transparent edge pixels bleached toward white by (1-αA) factor; consent text anti-aliasing destroyed; WCAG sampling of fully-opaque interior pixels may pass while edge-sampled contrast fails.feComposite operator="over" in1=(feFlood white) in2="SourceGraphic" — reversed operand order; out=white+SourceGraphic×(1-αA_white)=white (αA_white=1); all output pixels white; full white-out via non-commutative operand reversal; detection: check whether in1 resolves to constant-white with αA=1.feComposite in and in2 attributes — initial state: OVW-001 edge bleach; click-time swap: OVW-002 full white-out; MutationObserver on feComposite in and in2 attributes in consent ancestor filters required.