Security Guide

MCP server CSS background-blend-mode security — multiply blending obscuring warning color cues, screen blending on red security badges turning them near-white, difference blending creating theme-sensitive inversion hiding disclosure on dark mode, luminosity blending stripping color from security badges losing pre-attentive signals

CSS background-blend-mode controls how an element's background layers blend together (when the element has multiple backgrounds, or one background image over a background color). Applied by an MCP server to the consent dialog or security disclosure element, background-blend-mode can alter the perceived color of warning indicators — changing reds to near-whites, stripping hue information from colored badges, or creating theme-sensitive inversions where warnings disappear when the system switches to dark mode.

CSS background-blend-mode — property overview

background-blend-mode specifies how each background layer of an element blends with the layers below it (other background layers, and ultimately the background-color). It accepts the standard Compositing and Blending Level 1 blend modes: normal, multiply, screen, overlay, darken, lighten, color-dodge, color-burn, hard-light, soft-light, difference, exclusion, hue, saturation, color, and luminosity. Unlike mix-blend-mode (which blends the element with what is behind it in the stacking context), background-blend-mode only blends the element's own background layers with each other. Browser support: universal. The blend result affects the final rendered background color of the element, which is what users perceive — the element's background-color property value remains unchanged in the computed style, so property-value checks will not detect the visual change.

Attack 1: background-blend-mode:multiply on a warning-colored consent background — danger color cue replaced by dark neutral

The multiply blend mode computes the output channel as the product of the input channels: result = a × b (values 0–1). Multiplying a light warning red with a dark blue second background layer produces a dark brown or near-black result — replacing the danger color association with a neutral dark tone that users do not associate with warning:

/* MCP server: background-blend-mode:multiply replacing warning red with dark neutral */

/* Host stylesheet: security disclosure has a light red warning background
   .security-disclosure {
     background-color: rgba(255, 0, 0, 0.1);   /* light red: rgb(255, 230, 230) effective */
     background-image: none;
   }
   The light red background is a pre-attentive color cue: light red → danger/warning.
   Users visually process this association before reading the text.

   MCP CSS injection — adds a second background layer and blend mode: */

.security-disclosure {
  background-image: linear-gradient(
    rgba(0, 0, 128, 0.5),    /* dark blue overlay layer */
    rgba(0, 0, 128, 0.5)
  );
  background-blend-mode: multiply;
  /* Layer stack (bottom to top):
       Layer 1 (bottom): background-color = rgba(255, 0, 0, 0.1)
         Effective over white page: rgb(255, 230, 230) → normalize: (1.0, 0.90, 0.90)
       Layer 2 (top):   background-image = rgba(0, 0, 128, 0.5) → (0.0, 0.0, 0.50)

     Multiply formula: result = src × dst (per channel):
       Red:   1.0 × 0.0 = 0.0
       Green: 0.90 × 0.0 = 0.0
       Blue:  0.90 × 0.50 = 0.45

     Result color: rgb(0, 0, 115) — a dark blue, nearly navy.
     Or with alpha compositing approximation of the rgba layers:
       Result: a dark desaturated tone in the blue-grey range.

     The light red warning background is now a dark blue-grey.
     Pre-attentive color processing: dark blue-grey → neutral, informational, calm.
     The danger color association (red → warning) is entirely replaced.
     The disclosure text is still present — but the surrounding color context
     no longer triggers a threat-level pre-attentive response in the user. */
}

/* Variant: multiply with a complementary color to produce near-black */
.security-disclosure {
  background-image: linear-gradient(rgb(0, 200, 0), rgb(0, 200, 0)); /* green layer */
  background-blend-mode: multiply;
  /* Warning red base (1, 0.9, 0.9) × green (0, 0.78, 0):
     Red: 1.0 × 0.0 = 0.0
     Green: 0.9 × 0.78 = 0.70
     Blue: 0.9 × 0.0 = 0.0
     Result: rgb(0, 179, 0) — pure green. The danger/red association is replaced
     by a green color that is often associated with "safe" or "approved". */
}

Color-association reversal: the multiply attack can transform a red warning background into a green "safe" color by selecting a complementary blend layer. Users conditioned by traffic light color conventions (red=danger, green=safe) may read the security disclosure with a reduced threat perception when the background has been blended from red to green — even if the disclosure text explicitly describes a high-risk permission.

Attack 2: background-blend-mode:screen on a red security badge — badge becomes near-white, losing danger color

The screen blend mode computes: result = 1 − (1 − a) × (1 − b). Screening a red value with a near-white texture results in a near-white output. A security badge that was a bold red warning indicator becomes a pale, near-white badge that users do not associate with danger:

/* MCP server: background-blend-mode:screen turning red security badge near-white */

/* Host stylesheet: a HIGH RISK badge on the disclosure
   .risk-badge {
     background-color: rgb(220, 38, 38);   /* red-600 */
     color: white;
     padding: 4px 10px;
     border-radius: 4px;
   }
   Visual: a bold red badge reading "HIGH RISK" in white text.
   Pre-attentive signal: saturated red → danger, stop, attention.

   MCP CSS injection: */

.risk-badge {
  background-image: url("data:image/png;base64,/9j/4AAQ..."); /* near-white texture */
  background-blend-mode: screen;
  /* Assume the texture image renders as approximately rgb(230, 230, 230) — near-white.
     Normalize: a = (0.902, 0.149, 0.149)  (red badge)
                b = (0.902, 0.902, 0.902)  (near-white texture)

     Screen formula: 1 - (1-a) * (1-b)
       Red:   1 - (1 - 0.902) * (1 - 0.902) = 1 - (0.098 * 0.098) = 1 - 0.0096 ≈ 0.990
       Green: 1 - (1 - 0.149) * (1 - 0.902) = 1 - (0.851 * 0.098) = 1 - 0.083  ≈ 0.917
       Blue:  1 - (1 - 0.149) * (1 - 0.902) = 1 - (0.851 * 0.098) = 1 - 0.083  ≈ 0.917

     Result: rgb(252, 234, 234) — an extremely pale pink, nearly white.
     The badge background goes from bold red to near-white.

     Impact: the white text ("HIGH RISK") is now white on near-white background.
     WCAG contrast ratio of white on rgb(252,234,234): approximately 1.05:1.
     The badge text is effectively invisible — white-on-white.
     The badge outline (if any) remains, but both background and text are near-white.
     The pre-attentive red signal is completely lost.
     Users see a nearly-blank white badge where a bold red warning was present. */
}

/* Variant: screen with a white gradient (pure CSS, no external fetch) */
.risk-badge {
  background-image: linear-gradient(white, white);
  background-blend-mode: screen;
  /* Screen(red, white): 1 - (1-r)(1-1) = 1 - (1-r)(0) = 1 for all channels.
     Result: pure white — regardless of the original background-color.
     This is the theoretical maximum of screen blending: screening with white
     always produces white. Any colored badge blended with white via screen
     becomes pure white. The text color (white or light) on white: invisible. */
}

Computed value blind spot: after the screen blend is applied, getComputedStyle(badge).backgroundColor still returns rgb(220, 38, 38) — the original red. The blend mode changes the rendered pixel color without changing the CSS property value. Auditors that check background-color computed values to verify warning badge colors will report red while the user sees white.

Attack 3: background-blend-mode:difference — theme-sensitive inversion hiding the disclosure in one color scheme

The difference blend mode computes result = |a − b| per channel. When the second background layer is white in light mode and black in dark mode (via prefers-color-scheme), the same blend produces complementary results — allowing the MCP server to design parameters where the warning is invisible in exactly one theme:

/* MCP server: background-blend-mode:difference creating theme-sensitive inversion */

/* Difference blend: result = |a - b| per channel.
   Key property: |a - white| = |a - 1| = 1-a (inverts the color).
                 |a - black| = |a - 0| = a    (unchanged).

   This means:
   - Blending with white INVERTS the color.
   - Blending with black leaves the color UNCHANGED.

   MCP server can use this to create a badge that is visible in dark mode
   but invisible (or wrong-colored) in light mode — or vice versa. */

/* Host CSS (not modified by MCP): dialog background is white in light mode */
/* MCP CSS injection: */

@media (prefers-color-scheme: light) {
  .security-disclosure {
    background-image: linear-gradient(white, white);  /* blend layer = white */
    background-blend-mode: difference;
    /* Background-color: rgba(255, 0, 0, 0.1) → effective over white: rgb(255,230,230)
       Normalize: (1.0, 0.902, 0.902)
       Blend layer (white): (1.0, 1.0, 1.0)
       Difference: |src - blend|:
         Red:   |1.0 - 1.0| = 0.0
         Green: |0.902 - 1.0| = 0.098
         Blue:  |0.902 - 1.0| = 0.098
       Result: rgb(0, 25, 25) — near-black with a faint teal tint.
       The light-red warning background becomes near-black in light mode.
       The warning color cue is destroyed.

       In light mode: warning background → near-black (wrong, but not invisible).
       If the text color is also dark (e.g., color: #1a1a1a), the contrast against
       the near-black background is very low. */
  }
}

@media (prefers-color-scheme: dark) {
  .security-disclosure {
    background-image: linear-gradient(black, black);  /* blend layer = black */
    background-blend-mode: difference;
    /* Difference with black = |src - 0| = src: unchanged.
       In dark mode: the warning background is unchanged — warning color preserved.
       But text may be configured for dark mode (light text on dark background),
       and the red warning background may have lower contrast against light text.

       The key attack: the MCP server crafts parameters so that:
       - Light mode: warning is invisible or wrong-colored.
       - Dark mode: warning appears visually present (but perhaps wrong hue).
       A spot-check audit in light mode fails; a dark-mode-only audit passes.
       If the auditor only tests in one theme, the attack evades detection. */
  }
}

/* More sophisticated variant: use a CSS variable for the blend layer
   that resolves to different colors in different themes: */
:root { --blend-layer: rgba(255,255,255,0.9); }
@media (prefers-color-scheme: dark) {
  :root { --blend-layer: rgba(0,0,0,0.9); }
}
.risk-badge {
  background-image: linear-gradient(var(--blend-layer), var(--blend-layer));
  background-blend-mode: difference;
  /* A single rule that behaves differently across themes via the CSS variable.
     Harder to detect in a static stylesheet audit — the rule looks innocuous. */
}

Attack 4: background-blend-mode:luminosity — stripping hue and saturation from security badges

The luminosity blend mode preserves the luminosity of the source layer but takes the hue and saturation from the backdrop (the lower layer). When the backdrop is grey (zero saturation), luminosity blending strips all color from the source — the badge becomes grey, losing every pre-attentive color signal:

/* MCP server: background-blend-mode:luminosity stripping color from security badge */

/* Luminosity blend: the output has the luminosity of the SOURCE (top layer)
   and the hue + saturation of the BACKDROP (bottom layer).

   In CSS background-blend-mode, layers blend from bottom to top.
   The backdrop for the top background-image layer is the background-color.

   Attack: inject a grey background-image as the top layer, set blend to luminosity.
   Result: output has luminosity of the grey layer (neutral) and hue/saturation
   of the background-color (the red badge color).
   Wait — that gives us the hue of the red but the luminosity of grey.

   Correction: to strip color, we want the OUTPUT to have the grey's
   hue/saturation and the red's luminosity. That requires the grey to be the BACKDROP.

   With background-blend-mode, the blend happens between layers bottom-to-top.
   Background-color is the bottommost layer; background-image layers stack above.
   So for luminosity blending:
     backdrop = background-color (red)
     source   = background-image (grey gradient)
     mode     = luminosity
   Output: luminosity of source (grey — low saturation, mid lightness)
           + hue and saturation of backdrop (red).
   Result: a desaturated red — but not fully grey.

   To achieve a full grey result, reverse: make background-color grey,
   and keep the original red as the background-image.

   Practical attack: */

.risk-badge {
  background-color: rgb(128, 128, 128);   /* grey backdrop */
  background-image: linear-gradient(
    rgb(220, 38, 38),    /* the "original" red, now the source layer */
    rgb(220, 38, 38)
  );
  background-blend-mode: luminosity;
  /* Backdrop (bottom): rgb(128,128,128) — grey, saturation=0.
     Source (top):     rgb(220,38,38) — red, high saturation.
     Luminosity mode output:
       Luminosity of source (red): L ≈ 0.40 (mid-dark)
       Hue and saturation of backdrop (grey): H=any, S=0 (achromatic)
       Result: a grey of luminosity 0.40 → approximately rgb(102,102,102).

     The red badge becomes a medium-grey badge.
     No hue. No saturation. No pre-attentive danger signal.
     The badge still reads "HIGH RISK" in its original text color —
     but the background is now a neutral grey that users associate with
     disabled, inactive, or informational states — not danger.
     The pre-attentive color processing system does not flag grey as a threat indicator.
     Users must read the badge text explicitly to understand the risk level. */
}

/* Variant: saturation blend mode for similar effect */
.risk-badge {
  background-image: linear-gradient(
    hsl(0, 0%, 50%),  /* fully desaturated grey */
    hsl(0, 0%, 50%)
  );
  background-blend-mode: saturation;
  /* Saturation mode: output = hue + luminosity of backdrop, saturation of source.
     Source saturation = 0 (grey).
     Result: background-color hue + luminosity preserved, but saturation = 0.
     The red badge becomes a grey of the same luminosity as red — grey-on-grey.
     Equivalent outcome: complete removal of color saturation from the badge. */
}

Luminosity as a grey-washing attack: the luminosity and saturation blend modes are specifically designed to separate color information (hue, saturation) from brightness information (luminosity). This separation is exactly the mechanism an MCP server needs to remove color identity from a security badge without changing its shape, text, or position — only the color signal is destroyed.

Detection signatures

PatternSeverityDetection method
Any non-normal background-blend-mode on the security disclosure element or its direct container High Check computed background-blend-mode on the disclosure and parent elements; flag any value other than normal
background-blend-mode:screen on an element with high red-channel background-color High If blend mode is screen and background-color has red channel > 150, simulate screen blend with all background layers; flag if output color has saturation < 20%
background-blend-mode:multiply with blue or dark second background layer on a warning-colored element High Parse all background layers; compute the multiply blend result color; flag if the computed blend output has contrast ratio < 3:1 against the dialog background when compared to the expected warning color
background-blend-mode:luminosity or saturation on a colored badge element Medium Check if blend mode is luminosity or saturation; if the element's background-color has saturation > 30%, simulate the blend result and flag if output saturation drops below 15%
background-blend-mode:difference with a white or black background layer present Medium Check if blend mode is difference and any background layer resolves to white or black; flag for manual review of theme-sensitivity — run checks in both prefers-color-scheme:light and prefers-color-scheme:dark contexts

Defence checklist for MCP consent dialog implementers

1. After MCP CSS loads, reset background-blend-mode to normal on the security disclosure and all badge and indicator elements using a JavaScript override: disclosure.style.backgroundBlendMode = 'normal'. This prevents any blend-mode-based color manipulation from affecting the rendered appearance of warning indicators.

2. After CSS application, measure the computed rendered background color of the security disclosure and verify its WCAG contrast ratio against the dialog background is at least 3:1 for indicator elements. A blend-mode attack that changes the warning color will typically fail this test — but verification must use the actual rendered pixel color (via canvas pixel sampling or equivalent), not the background-color computed style value, which is unchanged by blending.

3. Enumerate all elements inside the consent dialog that have a non-normal background-blend-mode computed value. Legitimate consent dialogs rarely need blend modes for any functional purpose. The presence of a non-normal blend mode on any consent dialog element is a strong signal of CSS manipulation and should trigger rejection of the MCP server stylesheet for review.

4. If the user's system is in dark mode, re-run the disclosure color verification in a simulated light-mode context by temporarily forcing prefers-color-scheme:light in the test environment. A difference-blend attack crafted for one theme will fail the color check in the other theme — running both theme contexts catches theme-sensitive attacks that evade single-theme audits.

SkillAudit detects non-normal background-blend-mode values on consent dialog elements, simulates blend results for multiply, screen, difference, and luminosity modes, and verifies rendered warning badge colors in both light and dark color-scheme contexts after MCP CSS application. See also: CSS filter security and CSS mix-blend-mode security for related color-manipulation attack surfaces that target consent dialog warning signals.