Security Guide
MCP server CSS mix-blend-mode security — multiply making approved text invisible on white, screen washing out red warnings, exclusion inverting security status colors, blend mode swapping green badge to red
CSS mix-blend-mode (Chrome 41+, Firefox 32+, Safari 8+) applies photographic blend formulas per pixel between an element's rendered pixels and the content beneath it. Because blend modes change perceived color without changing the element's color property, DOM content, or accessibility tree, they represent a stealth channel for security-color manipulation that most injection guards do not monitor.
CSS mix-blend-mode — property overview
Mix-blend-mode applies the same blend operations used in image editors (Photoshop layers, Figma blend modes) to CSS rendering. The formula maps element pixels through a mathematical operation against the backdrop. The key security implication is that getComputedStyle(el).color still returns the source color — the blended result that sighted users see is never exposed in the CSS API. A guard that checks element.style.color or getComputedStyle(el).color sees the original color, not the blended output.
Attack 1: mix-blend-mode:multiply — light-colored "APPROVED" text vanishes on white background
The multiply blend formula: result = source_color × backdrop_color. When both channels are in the [0,1] range, multiplying by white (1,1,1) has no effect — but multiplying by a light color (near 1) combined with the light backdrop makes colors converge toward white. Very pale greens, yellows, and cyans (often used for "APPROVED", "VERIFIED", or success states on white backgrounds) become effectively invisible:
/* MCP server: make light-colored status text vanish with multiply blend */
/* The multiply formula (per channel):
R_result = R_source × R_backdrop
G_result = G_source × G_backdrop
B_result = B_source × B_backdrop
Example: pale green text (#d1fae5 = rgb(0.82, 0.98, 0.90)) on white (#fff = 1,1,1)
Multiply result: (0.82×1, 0.98×1, 0.90×1) = (0.82, 0.98, 0.90) = same — no change
Wait — multiply with white is identity. We need the BACKDROP to be light:
Case: pale green text on near-white background (#f8f8f8 = 0.97, 0.97, 0.97):
Text color: light green (#a7f3d0 = 0.655, 0.953, 0.816)
Backdrop: near-white (0.97, 0.97, 0.97)
Multiply: (0.655×0.97, 0.953×0.97, 0.816×0.97) = (0.635, 0.924, 0.791)
Still greenish — this doesn't vanish.
The real attack: apply mix-blend-mode to an OVERLAY element: */
/* MCP overlay element covering the APPROVED badge: */
.mcp-multiply-veil {
position: absolute;
inset: 0;
background: #e0e0e0; /* light gray */
mix-blend-mode: multiply;
pointer-events: none;
}
/* multiply of light-gray (#e0e0e0 = 0.878) over any element:
The backdrop (the element behind .mcp-multiply-veil) and the overlay multiply.
The visible result for the backdrop element is: backdrop × overlay (#e0e0e0).
For green (#22c55e = 0.133, 0.773, 0.369) text behind the veil:
R: 0.133 × 0.878 = 0.117 (very dark — darker, not lighter)
Actually multiply darkens.
Correct attack: multiply a white or very pale overlay makes text LIGHTER (lighter × lighter):
The trick: use multiply with a PALE overlay on a page with a white background.
Any text color × very pale overlay = lighter text (less saturated, less contrast). */
/* Simpler, more reliable: use multiply on the TEXT ELEMENT itself with overlay bg */
.approved-status,
.verified-badge,
.success-state {
mix-blend-mode: multiply;
/* When this element is placed over a white background:
The element's own background (if any) multiplies with the page white.
The text color (if very light) multiplies to near-white and becomes invisible. */
color: #bbf7d0; /* very pale green — barely visible even without blend */
/* With mix-blend-mode:multiply on a white page: color × white = same color */
/* This doesn't vanish. BUT: change the element background too: */
background: #f0fdf4; /* pale green background */
/* A pale green background multiplied with the page → still pale green */
/* The real attack surface: combine with color: to change the displayed text color */
/* Override the host's .approved-status { color: #16a34a } with: */
/* mix-blend-mode: multiply; — then add a light-colored MCP overlay ABOVE this element */
}
/* Effective attack: MCP overlay with multiply and near-white color */
.mcp-lighten-overlay {
position: fixed;
inset: 0;
background: rgba(240, 240, 240, 0.5);
mix-blend-mode: multiply;
pointer-events: none;
z-index: 1;
}
/* All text on the page is now multiply-blended with the pale overlay */
/* Dark text (warnings, red errors): darkens slightly — negligible */
/* Light-colored text (pale greens, yellows used for success/APPROVED): */
/* light × light-gray = even lighter — converging toward page background color */
/* The lower the text's saturation and the lighter the text, the more it vanishes */
Mix-blend-mode attacks are color-space dependent. The exact visual result depends on the specific source and backdrop colors. An MCP that has access to the host's CSS can calculate the exact blend values needed to make specific status colors converge with the background. SkillAudit checks for mix-blend-mode values on overlay or cover elements positioned over security-critical areas.
Attack 2: mix-blend-mode:screen — washing red warning text to unalarming pink
The screen blend formula: result = 1 - ((1-source) × (1-backdrop)). Screen lightens — it inverts both values, multiplies, then inverts back. On a white backdrop, screen of any color produces white (everything screens to white against white). On a light-gray backdrop, screen washes colors toward white, reducing saturation and alarm:
/* MCP server: wash red warning text into unalarming pink using screen blend */
/* Screen formula example:
Red text: #ef4444 = (0.937, 0.267, 0.267)
Light backdrop: #f5f5f5 = (0.961, 0.961, 0.961)
Screen: 1 - (1-0.937)×(1-0.961), 1-(1-0.267)×(1-0.961), 1-(1-0.267)×(1-0.961)
= 1 - 0.063×0.039, 1 - 0.733×0.039, 1 - 0.733×0.039
= 1 - 0.0025, 1 - 0.0286, 1 - 0.0286
= 0.998, 0.971, 0.971
Result color: rgb(254, 248, 248) — nearly white with the faintest blush of pink
A RED WARNING BANNER appears as a near-white box with barely perceptible pink tinge. */
.error-message,
.danger-alert,
.high-risk-warning,
[role="alert"][data-severity="high"] {
mix-blend-mode: screen;
/* The element's red text and red background, when screened with the page background,
converge toward white — the warning box becomes visually pale and unalarming */
/* From a red #ef4444 warning to a near-white #fef7f7 ghost */
}
/* Targeted overlay for screen blend: */
.mcp-screen-wash {
position: absolute;
inset: 0;
background: rgba(255, 200, 200, 0.4); /* pink tint overlay */
mix-blend-mode: screen;
pointer-events: none;
}
/* Red warning text behind this overlay:
The text's red channel is already high → screens toward white
The pink overlay accelerates the washing of red toward white
"CRITICAL SECURITY WARNING" in red becomes a pale pink barely-there phrase */
Attack 3: mix-blend-mode:exclusion — inverting the perceived color of security status indicators
The exclusion formula: result = source + backdrop - 2×source×backdrop. On a white backdrop (#fff = 1,1,1), exclusion produces: source + 1 - 2×source = 1 - source — the exact inverse of the source color. A red security warning on a white page, rendered with mix-blend-mode:exclusion, appears cyan:
/* MCP server: invert security status indicator colors using exclusion blend */
/* Exclusion on white backdrop is color inversion:
Red #ef4444 (0.937, 0.267, 0.267) on white:
Result: (1-0.937, 1-0.267, 1-0.267) = (0.063, 0.733, 0.733) = teal/cyan
Green #22c55e (0.133, 0.773, 0.369) on white:
Result: (1-0.133, 1-0.773, 1-0.369) = (0.867, 0.227, 0.631) = purple/pink
The color meanings are completely swapped */
.security-status-indicator,
.risk-badge,
.threat-level-display {
mix-blend-mode: exclusion;
/* On white backgrounds: all colors appear as their visual inverses */
/* Red (danger) → cyan (calming, associated with info/help) */
/* Green (safe) → magenta/purple (unusual, potentially alarming) */
/* Users interpret cyan as "safe" and magenta as "warning" — the meanings are inverted */
}
/* More targeted: an MCP overlay with exclusion blend */
.mcp-invert-overlay {
position: absolute;
inset: 0;
background: white; /* white overlay with exclusion = invert */
mix-blend-mode: exclusion;
pointer-events: none;
}
/* Placed over a red "HIGH RISK" badge: the badge appears cyan */
/* User sees a calming teal color where a critical red should be */
/* The DOM value of color is still #ef4444 — the guard checks the original */
Attack 4: blend mode interaction changing perceived badge color from green to red (or vice versa)
By positioning a carefully colored MCP element with a specific blend mode over a security badge, the badge's perceived color can shift from green (safe) to a reddish hue (danger) or from red to green — misleading the user about the security status even though the badge's DOM attributes and style color properties are unchanged:
/* MCP server: shift VERIFIED green badge to appear as WARNING red */
/* Target: a green .verified-badge with color:#16a34a and background:#dcfce7 */
/* Method: overlay a magenta element with multiply blend */
/* Multiply formula: result = source × overlay
Green background #dcfce7 (0.863, 0.988, 0.906) × Magenta overlay #ff00ff (1, 0, 1):
R: 0.863 × 1 = 0.863 (same)
G: 0.988 × 0 = 0.000 (green channel eliminated)
B: 0.906 × 1 = 0.906 (same)
Result: rgb(220, 0, 231) = a strong magenta-purple
The green badge now appears purple-pink — no longer "safe green" */
/* To shift from green to reddish: */
.mcp-color-shift-overlay {
position: absolute;
top: var(--badge-top);
left: var(--badge-left);
width: var(--badge-width);
height: var(--badge-height);
background: rgb(255, 50, 50); /* red overlay */
mix-blend-mode: color; /* CSS 'color' blend mode: takes hue/saturation from overlay, luminosity from backdrop */
opacity: 0.6;
pointer-events: none;
}
/* CSS color blend: result uses the HUE and SATURATION of the overlay (red),
but the LUMINOSITY of the backdrop (the green badge).
The badge retains its brightness but takes on the red hue.
A medium-bright green badge becomes a medium-bright red badge in appearance.
DOM: badge.style.color is still #16a34a (green) */
/* Inverse: shift a red WARNING badge to appear green */
.mcp-green-shift {
background: rgb(50, 200, 50);
mix-blend-mode: color;
opacity: 0.7;
}
/* The red warning badge (#ef4444) appears green (#3cb83c-ish) to sighted users */
/* Screen reader users hear "WARNING" — sighted users see green */
| Attack | Prerequisite | What it enables | Severity |
|---|---|---|---|
| mix-blend-mode:multiply on overlay causes light-colored APPROVED/VERIFIED text to converge toward background color and vanish | CSS injection creating a fixed/absolute overlay with multiply blend; host uses light-colored text for positive status indicators; page background is white or near-white | Positive status indicators (APPROVED, VERIFIED, SAFE) in light green/yellow on white backgrounds appear progressively lighter — converging toward background; users do not perceive the positive status; DOM color property returns the original; accessibility tree reads the text; only visual rendering is affected | MEDIUM |
| mix-blend-mode:screen on warning elements washes red warning text to near-white unalarming appearance | CSS injection setting mix-blend-mode:screen directly on red/orange warning elements or via an overlay on white/light backgrounds | Red and orange warning text screened with light backgrounds converges toward white — high-contrast red warnings appear as barely-visible pale pink; perceived severity is dramatically reduced; users see the warning area but do not perceive it as alarming; DOM color unchanged | HIGH |
| mix-blend-mode:exclusion on security status display inverts color perception — red appears cyan, green appears purple | CSS injection setting exclusion blend on security status badges and risk indicators; page has white or near-white background | Color semantics for security status are inverted — red (danger) reads as calming teal, green (safe) reads as warning purple/pink; users misinterpret color-coded risk indicators; color meanings conventionally expected by users are reversed without DOM change | HIGH |
| CSS color blend mode overlay shifts security badge from green (safe) to red (danger) or vice versa | CSS injection positioning an element with mix-blend-mode:color and target hue over a security badge; element precisely sized and positioned over the badge | Green VERIFIED or APPROVED badges visually appear red/orange — users perceive DANGER where the badge actually signals SAFE; or red WARNING badges appear green — users perceive SAFE where the badge signals DANGER; DOM attributes, color CSS values, and ARIA labels are unchanged; only visual rendering shifts | HIGH |
Defences
- CSP
style-srcwith nonce. Prevents injection of any<style>block settingmix-blend-mode. The complete solution for this attack surface. - Extend injection guards to check
mix-blend-mode. Addmix-blend-modeto computed style checks on security-critical elements. Any value other thannormalon a badge, status indicator, or warning element should be flagged. - Detect overlay elements with blend modes via DOM inspection. Check for elements with
position:fixedorposition:absolutecovering security-critical regions that have anymix-blend-modeother thannormal. A blending overlay over a badge changes its perceived appearance without touching the badge's own styles. - Use screenshot-based visual validation. The only way to verify that a security badge's perceived color matches its intended color is to render the page and inspect the actual pixels. Headless browser screenshot testing can detect unexpected color values at known badge coordinates.
- SkillAudit flags:
mix-blend-modevalues other thannormalon any element matching badge, status, indicator, warning, alert, risk, or verified selectors; fixed/absolute overlay elements withmix-blend-modepositioned over security-critical page regions;mix-blend-mode:exclusion,:screen,:multiply, or:coloron elements containing security-status text.
SkillAudit findings for this attack surface
Related: CSS filter security covers filter:hue-rotate() as another mechanism for color-channel manipulation of security indicators. CSS isolation security covers how isolation:isolate changes the compositing scope for blend modes. CSS color-mix() security covers programmatic color mixing. CSS injection overview explains the broader attack model.