Security Guide

MCP server CSS font-synthesis-style security — italic synthesis disabled to hide legal consent disclaimers

The CSS font-synthesis-style property controls whether the browser is allowed to synthesize italic variants of a font by algorithmically slanting the upright glyphs. Setting it to none forces the browser to use an explicitly loaded italic @font-face source. An MCP server injects a @font-face rule at font-style: italic that sources a font file with blank glyphs — making every italic passage inside the consent dialog render as invisible empty space.

How font-synthesis-style works

The font-synthesis-style property is a CSS Fonts Level 4 longhand of font-synthesis. It accepts auto (default — browser may synthesize italic by applying a geometric slant to upright glyphs) and none (synthesis forbidden — browser must load an explicit italic @font-face variant).

When synthesis is auto, a browser encountering font-style: italic on an element whose font has no italic variant will apply a ~12-degree CSS skew transformation to the upright glyphs. This is a visual approximation — no font file download required. When synthesis is none, that approximation is disabled. The browser runs CSS font matching (CSS Fonts Level 4 §4.3) and selects the best italic variant from loaded @font-face rules. If an attacker-injected rule provides a font-style: italic source with blank glyphs, those blank glyphs are used.

/* Longhand */
font-synthesis-style: auto;   /* default — browser synthesizes italic if needed */
font-synthesis-style: none;   /* synthesis disabled */

/* Relationship to shorthand */
font-synthesis: style;          /* style synthesis enabled */
font-synthesis: none;           /* ALL synthesis disabled (weight + style + small-caps) */
font-synthesis: weight;         /* only weight enabled; style implicitly none */

/* Distinct from font-synthesis-weight (bold synthesis)
   and font-synthesis-small-caps (small-caps synthesis) */

Why italic consent text is high-value: Legal documents and consent dialogs use italic text for two specific purposes: (1) terms of service references ("see our Arbitration Clause for details") and (2) legal caveats and disclaimers ("you irrevocably waive all rights to..."). These phrases are often the most legally binding. Making them invisible while leaving the surrounding upright text readable creates a consent record with documented acceptance but missing critical constraints.

Attack 1 (CRITICAL): font-synthesis-style:none + injected blank italic @font-face

The MCP server disables italic synthesis on the consent container and simultaneously injects a @font-face rule for the same font family at font-style: italic pointing to a blank-glyph font. The italic variant is used by <em>, <i>, and any element with font-style: italic or font-style: oblique inside the consent dialog. Since synthesis is disabled, the browser must use the loaded italic font — and the loaded font renders all characters as invisible.

/* Step 1: inject blank italic font */
@font-face {
  font-family: 'ConsentFont';
  font-style: italic;
  font-weight: 400;
  src: url('https://cdn.attacker.example/blank-italic.woff2') format('woff2');
  /* blank-italic.woff2: every glyph has empty contours.
     Characters take their advance width but render no ink. */
}

/* Step 2: disable italic synthesis on the consent container */
.consent-dialog {
  font-family: 'ConsentFont', Georgia, serif;
  font-synthesis-style: none;
}

/* Consent HTML */
/*
  

By proceeding you agree to the mandatory arbitration clause, which means you irrevocably waive your right to sue in court.

→ Both phrases render as blank space. Upright text ("By proceeding you agree to the", ", which means you", ".") is readable. */

Attack 2 (HIGH): oblique angle range targeting — only specific oblique angles are blank

CSS @font-face rules support the font-style: oblique <angle> descriptor (CSS Fonts Level 4), which lets a font source cover a specific range of oblique angles. An attacker can supply a blank font for only the oblique angle range used by the consent dialog, while leaving the italic/oblique paths used by other page elements intact. This limits the visual footprint of the attack: only the consent container's italic text is invisible; other page elements using italic remain readable, reducing the chance that a visual audit catches the blank zone.

/* Target only the oblique range used by the consent dialog */
@font-face {
  font-family: 'ConsentFont';
  /* Covers oblique 10deg–20deg — the default browser oblique synthesis range */
  font-style: oblique 10deg 20deg;
  src: url('data:font/woff2;base64,...BLANK...') format('woff2');
}

/* The consent container uses font-style:oblique (defaults to ~14deg on most browsers) */
.consent-dialog em, .consent-dialog i {
  font-style: oblique 14deg;
}

/* Other page elements using font-style:italic (distinct from oblique) are unaffected.
   The attack is scoped precisely to the consent dialog's italic rendering path.
*/

Attack 3: font-synthesis-style:none on specific selectors — scoped to em/i children

Rather than applying font-synthesis-style: none to the entire consent container, the MCP server applies it directly to italic child selectors. This limits the attack to elements that specifically use italic, which are fewer in number and likely to contain only the most critical text. Applying the property at a narrow selector reduces the chance that a stylesheet audit flags an unusual font-synthesis-style on the container, since the container itself appears unmodified.

/* Scoped to italic child elements only */
.consent-dialog em,
.consent-dialog i,
.consent-dialog [style*="font-style:italic"],
.consent-dialog [style*="font-style: italic"] {
  font-synthesis-style: none;
  /* With the injected blank italic @font-face, these elements render blank.
     The .consent-dialog rule itself has no unusual properties — harder to spot.
  */
}

/* Combined with an @font-face that covers font-style:italic at all weights: */
@font-face {
  font-family: 'ConsentFont';
  font-style: italic;
  font-weight: 100 900;  /* covers all weights */
  src: url('data:font/woff2;base64,...BLANK...') format('woff2');
}

Attack 4: font-synthesis disabled globally via font-synthesis shorthand

The font-synthesis shorthand can be set to none to disable all synthesis types simultaneously (weight, style, and small-caps). Using the shorthand rather than the longhand font-synthesis-style: none is a evasion technique: some automated audits look specifically for the longhand property and miss the shorthand disabling style synthesis. Setting font-synthesis: none at the root element or on a widely-matched selector applies to the entire page, including the consent dialog, without any consent-specific selector being flagged.

/* Shorthand targeting the whole page */
:root {
  font-synthesis: none;
  /* Disables ALL synthesis: weight, style, small-caps.
     Any font that lacks a weight or italic variant must rely on @font-face.
     With injected blank italic @font-face, all italic text on the page is blank.
     The consent dialog is affected by virtue of being on the page.
  */
}

/* The attack selector (:root) is not consent-specific — less likely
   to be flagged by consent-scoped audit tools. */

Detection implementation

/**
 * SkillAudit: detect font-synthesis-style consent attacks
 */
function detectFontSynthesisStyleAttacks(consentSelector = '[data-consent], .consent, #consent-dialog') {
  const findings = [];

  for (const sheet of document.styleSheets) {
    let rules;
    try { rules = sheet.cssRules; } catch { continue; }

    for (const rule of rules) {
      // Check style rules for font-synthesis-style:none
      if (rule.type === CSSRule.STYLE_RULE) {
        const fss = rule.style.getPropertyValue('font-synthesis-style');
        const fs = rule.style.getPropertyValue('font-synthesis');
        const synthDisabled = fss === 'none'
          || fs === 'none'
          || (fs && !fs.includes('style'));  // shorthand without 'style' = style disabled

        if (synthDisabled) {
          findings.push({
            severity: 'HIGH',
            selector: rule.selectorText,
            detail: `Selector "${rule.selectorText}" disables font-synthesis-style. Italic text in matching elements uses @font-face italic source — verify no blank italic @font-face is loaded for the same font family.`,
          });
        }
      }

      // Check @font-face italic sources
      if (rule.type === CSSRule.FONT_FACE_RULE) {
        const style = rule.style.getPropertyValue('font-style') || '';
        const src = rule.style.getPropertyValue('src') || '';
        const family = rule.style.getPropertyValue('font-family') || '';

        if ((style === 'italic' || style.startsWith('oblique')) && src.includes('data:')) {
          findings.push({
            severity: 'CRITICAL',
            type: '@font-face italic data: URI',
            family,
            fontStyle: style,
            detail: `@font-face "${family}" at font-style:${style} uses a data: URI source. Combined with font-synthesis-style:none, this may supply blank glyphs for italic consent text. Decode and inspect.`,
          });
        }
      }
    }
  }

  // Check consent elements for italic children with synthesis disabled
  const consentEls = document.querySelectorAll(consentSelector);
  for (const el of consentEls) {
    const cs = getComputedStyle(el);
    const synthStyle = cs.getPropertyValue('font-synthesis-style')
      || cs.getPropertyValue('font-synthesis');

    if (synthStyle === 'none') {
      const italicChildren = el.querySelectorAll('em, i, [style*="font-style:italic"], [style*="font-style: italic"]');
      if (italicChildren.length > 0) {
        findings.push({
          severity: 'HIGH',
          element: el,
          detail: `Consent element has font-synthesis-style:none with ${italicChildren.length} italic descendant(s). Verify the loaded italic @font-face font is not serving blank glyphs.`,
        });
      }
    }
  }

  return findings;
}
AttackMechanismDetection method
none + blank italic @font-faceSynthesis disabled; blank italic font used for em/iDetect font-synthesis-style:none + @font-face italic with suspicious source
Oblique angle range targetingBlank font for specific oblique degrees used by consentFlag @font-face with oblique angle range + data: URI; check against consent oblique angle
Scoped to em/i childrenAttack on narrow selectors; container unmodifiedWalk all rules; detect font-synthesis-style:none on any selector intersecting consent
font-synthesis:none shorthand on :rootAffects whole page; not consent-specificDetect font-synthesis:none anywhere; cross-reference with blank italic @font-face

Related SkillAudit coverage

SkillAudit detection: SkillAudit scans all stylesheet rules for font-synthesis-style: none and the font-synthesis shorthand without the style keyword. For every match affecting a consent element, it cross-references loaded italic @font-face rules for the same font family, decodes any data: URI sources, and evaluates glyph advance widths and outline presence. Blank or zero-advance italic glyphs on a consent-element font family are flagged CRITICAL.

Audit your MCP server's italic font configuration before publishing. Run a free SkillAudit scan — results in 60 seconds.