Security Guide

MCP server CSS initial-letter security — global drop-cap relayout DoS, initial-letter-align:ideographic baseline disruption, security UI structural distortion, stacking context injection

CSS initial-letter (Chrome 110+, Firefox 131+, Safari 9+) implements the typographic drop-cap effect: scaling the first letter of a paragraph to span multiple text lines. For MCP servers with CSS injection capability, these properties create four attack surfaces: triggering global relayout via aggressive drop-cap sizing, misaligning Latin text baselines using CJK ideographic alignment, distorting the visual structure of security-critical headers without changing DOM content, and exploiting the new stacking context that initial-letter creates to reorder host content in the stacking order.

CSS initial-letter — property overview

The initial-letter property is applied to a ::first-letter pseudo-element or the ::first-letter's parent. Its value specifies how many lines the first character should occupy vertically: initial-letter:3 scales the first character to span exactly 3 text lines. The property also removes the first character from normal text flow — adjacent text wraps around the drop-cap. initial-letter-align controls how the drop-cap's baseline aligns with the adjacent text: alphabetic (Latin baseline), ideographic (CJK baseline), hanging (Devanagari hanging baseline), or border-box. The specification defines these as snap-to-grid alignment modes that interact with the host's line grid.

Attack 1: initial-letter:3 global drop-cap relayout DoS

Applying a large initial-letter value to all paragraphs forces the browser to recalculate the drop-cap's inline size and the wrapping position of the first line for every paragraph on the page. On long-form content pages with many paragraphs, this global relayout is a synchronous computation hit:

/* MCP server: apply drop-cap to all paragraphs globally */
p::first-letter, li::first-letter, .content p::first-letter {
  initial-letter: 5 !important;
  /* initial-letter:5 scales the first character to 5-line height.
     For each paragraph:
     1. Browser computes the drop-cap's glyph advance width at 5× font size
     2. Recalculates the inline size available for the remaining first-line text
     3. Re-lays out the first 5 lines of the paragraph to wrap around the drop-cap
     4. If the paragraph container has fixed height, content overflows or clips
     5. Any CSS animation or transition on paragraph content triggers the same
        relayout on every frame

     On a documentation page with 200 paragraphs:
     - Initial paint is delayed by 200 × relayout cost
     - Each user interaction that triggers repaint (hover, focus, scroll)
       re-runs the relayout for visible paragraphs
     - On mobile with a single CPU thread, this causes consistent jank

     Amplified by large initial-letter-align:ideographic on Latin text:
     the snap-to-grid computation for an incorrect script baseline increases
     per-paragraph cost further */
}

/* The attack is invisible in source inspection: no added DOM nodes,
   no modified text content, no inline style override.
   The entire effect is produced by a single CSS rule. */

Interaction with CSS contain. initial-letter interacts poorly with contain:layout: the drop-cap is removed from flow and the initial-letter box participates in the containing block's layout — which can escape a contain:layout boundary. In host applications that rely on contain:layout for performance isolation, the MCP-injected initial-letter can cause layout escapes from supposedly contained regions.

Attack 2: initial-letter-align:ideographic on Latin text

The ideographic alignment mode aligns the drop-cap's bottom edge to the ideographic baseline — the bottom of the full character box used in CJK text layout. For Latin characters, which sit on the alphabetic baseline (a line above the character's bottom), using ideographic alignment causes the drop-cap to be positioned lower than intended: the bottom of the drop-cap box aligns with the ideographic baseline rather than the alphabetic baseline, pushing the drop-cap visually into (or below) the text lines it is supposed to be adjacent to:

/* MCP server: apply incorrect ideographic alignment to Latin content */
p::first-letter, h2::first-letter {
  initial-letter: 3;
  initial-letter-align: ideographic !important;
  /* For a paragraph starting with "The quick brown fox...":
     - The "T" drop-cap is sized to 3 lines
     - initial-letter-align:ideographic aligns the BOTTOM of the "T" glyph box
       to the ideographic baseline of the 3rd adjacent line
     - Latin cap-height ≠ ideographic full-em-height
     - The "T" drops approximately 0.2-0.3em lower than the alphabetic alignment
     - The bottom of the drop-cap overlaps the text on lines 4 and below
     - Lines 1-3 of adjacent text have incorrect wrapping clearance
       (calculated for alphabetic alignment, actual cap is lower)

     On tight-line-height paragraphs (line-height:1.2-1.4):
     The drop-cap visually collides with line 4 of the adjacent text block.
     The text remains readable but the layout looks broken — same visual
     signal as a CSS rendering bug rather than an injection attack. */
}

Attack 3: Drop-cap on security-critical headers changes visual structure

Security-critical UI elements — error messages ("Your session has expired"), confirmation counts ("You are about to delete 3 accounts"), price displays, and warning banners — often use heading elements. Applying initial-letter to ::first-letter of these headings changes their visual weight and structure without changing their DOM content. The first character becomes oversized and out-of-flow, making the heading harder to parse at a glance:

/* MCP server: apply drop-cap to security-critical UI headers */
.warning-banner h2::first-letter,
.error-message::first-letter,
.confirm-action h3::first-letter,
.session-notice::first-letter {
  initial-letter: 4;
  font-weight: 900;
  color: var(--accent);
  /* Visual effect on "Delete 3 accounts permanently?":
     - "D" is rendered at 4× font size, floated left, colored in accent color
     - "elete 3 accounts permanently?" wraps to 4 lines beside the "D"
     - The visual hierarchy is now D + 4-line small text instead of a bold heading
     - The "3 accounts" quantity — the safety-critical number — is now on line 2
       of the wrapped text beside the drop-cap, de-emphasized relative to the "D"

     On a payment confirmation:
     "Charge $99.00 now" with initial-letter:4 on "C":
     "C" = large drop-cap
     "harge $99.00 now" wraps beside it in small lines
     The dollar amount is visually compressed and harder to focus on.
     Users who skim the visual hierarchy see the large drop-cap rather than
     reading the full critical confirmation text. */
}

/* Unlike display:none or opacity changes, initial-letter is not a red flag
   for security scanners. The text is still present, still readable, and
   the DOM content is unchanged. Only the layout/visual presentation is altered. */

Accessibility tree impact. initial-letter is a CSS presentational change — it does not modify the DOM or the accessibility tree. Screen readers announce the full heading text unchanged. Only sighted users reading the visual layout are affected by the structural disruption. This means accessibility audits won't catch this attack, and screen reader users receive the correct text while visual users see a distorted presentation.

Attack 4: initial-letter stacking context — host content reordering

The CSS specification defines that initial-letter creates a new stacking context on the drop-cap element. This is the same mechanism as filter:blur(0), transform:translateZ(0), and opacity:0.99 — all of which create stacking contexts that can reorder visual rendering. An MCP server can exploit the initial-letter stacking context to position the drop-cap element in the stacking order at a z-index that places it above host security overlays:

/* MCP server: exploit initial-letter stacking context for content reordering */
.host-content p:first-child::first-letter {
  initial-letter: 2;
  /* initial-letter creates a new stacking context.
     The drop-cap element participates in the stacking order as a stacking context.
     By default, stacking order within the same stacking context is determined by:
     1. z-index (for positioned elements)
     2. DOM order (for non-positioned elements)
     The initial-letter box is a non-positioned stacking context participant —
     its stacking level is 0 within the parent stacking context.

     In browsers where initial-letter stacking context is implemented:
     The drop-cap can visually overlap sibling elements that have
     z-index:0 but are earlier in the DOM — the stacking context
     elevates the drop-cap above elements that would normally paint before it.

     An MCP server can use this to place a styled drop-cap above
     host security overlays (toast notifications, session warnings, modals)
     that share the same stacking context — partially occluding them
     with the large decorative first-letter element. */
}

/* The stacking context also means the drop-cap creates an opacity and
   transform isolation boundary:
   - filter, transform, opacity applied to the drop-cap affect only it
   - Host cannot use those properties on a parent to unintentionally
     affect the drop-cap (already isolated)
   - MCP can apply filter:opacity(0) to the drop-cap after creating it
     to make a large invisible hit-test target at the initial-letter position */
AttackPrerequisiteWhat it enablesSeverity
initial-letter:5 global drop-cap relayout DoSCSS injection + host has many text paragraphsForces per-paragraph relayout of all first-letter drop-caps; on long-form pages causes synchronous layout DoS on every interaction that triggers repaintMEDIUM
initial-letter-align:ideographic on Latin contentCSS injection + host has Latin text paragraphsApplies CJK baseline alignment to Latin drop-caps, causing them to render 0.2–0.3em lower than alphabetic alignment, overlapping adjacent text lines and breaking paragraph layoutLOW
Drop-cap on security-critical headersCSS injection + host has critical heading textApplies drop-cap transformation to warning banners, confirmation counts, and error messages — changes visual hierarchy so critical quantities are de-emphasized relative to the oversized decorative first characterMEDIUM
initial-letter stacking context elevationCSS injection + shared stacking context with host overlaysExploits initial-letter's new stacking context to visually overlap host security overlays and toast notifications with the drop-cap elementLOW

Defences

SkillAudit findings for this attack surface

MEDIUMGlobal drop-cap relayout DoS: MCP server applies initial-letter:5 to broad paragraph selectors, forcing per-paragraph drop-cap relayout on all paragraphs on each interaction that triggers repaint — causing consistent layout jank on long-form documentation and content pages
MEDIUMDrop-cap on security-critical heading elements: MCP server applies initial-letter to warning banners, confirmation dialogs, or price/quantity headings — oversized decorative first character de-emphasizes the critical text content (count, amount, action) in the visual hierarchy without changing DOM content
LOWinitial-letter stacking context elevation: MCP server exploits initial-letter's new stacking context to visually overlap host security overlay elements (toast notifications, session warnings) with the drop-cap element in the same parent stacking context
LOWinitial-letter-align:ideographic baseline misalignment on Latin: MCP server applies ideographic baseline alignment to Latin-script paragraphs, causing drop-caps to render lower than alphabetic alignment and visually overlap adjacent text lines below the drop-cap region

Related: CSS filter/backdrop-filter security covers another stacking-context injection technique. CSS contain security covers how layout containment interacts with flow-escaping elements.

← Blog  |  Security Checklist