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 */
| Attack | Prerequisite | What it enables | Severity |
|---|---|---|---|
| initial-letter:5 global drop-cap relayout DoS | CSS injection + host has many text paragraphs | Forces per-paragraph relayout of all first-letter drop-caps; on long-form pages causes synchronous layout DoS on every interaction that triggers repaint | MEDIUM |
| initial-letter-align:ideographic on Latin content | CSS injection + host has Latin text paragraphs | Applies 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 layout | LOW |
| Drop-cap on security-critical headers | CSS injection + host has critical heading text | Applies 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 character | MEDIUM |
| initial-letter stacking context elevation | CSS injection + shared stacking context with host overlays | Exploits initial-letter's new stacking context to visually overlap host security overlays and toast notifications with the drop-cap element | LOW |
Defences
- Explicitly set
initial-letter: normalon security-critical elements. Apply::first-letter { initial-letter: normal !important }within the host's stylesheet scope for error messages, warning banners, confirmation dialogs, and price/quantity displays to prevent MCP override. - CSP
style-srcblocks MCP injection of stylesheets that useinitial-letteron host elements. - Avoid shared stacking contexts between host security overlays and MCP content areas. Ensure modal overlays and session warning banners are in a separate stacking context (using
isolation:isolateor a dedicated high-z-index container) that MCP elements cannot share. - Performance monitoring: unexpected first-paint delays on long-form pages with many paragraphs may indicate a global
initial-letterinjection. Check for::first-letterpseudo-element rules in MCP-injected stylesheets during security audits. - SkillAudit flags:
initial-lettervalues above 1 applied to broad selectors (p::first-letter,li::first-letter, universal selectors);initial-letter-align:ideographicon non-CJK content; anyinitial-letterapplied to elements with selectors suggesting security-critical UI (warning, error, confirm, alert, notice).
SkillAudit findings for this attack surface
Related: CSS filter/backdrop-filter security covers another stacking-context injection technique. CSS contain security covers how layout containment interacts with flow-escaping elements.