Security Guide

MCP server CSS word-break security — break-all splitting security keywords mid-character, overflow-wrap:anywhere breaking amounts at digit boundaries, keep-all overflowing CJK notices, hyphens:auto mangling security words

CSS word-break and overflow-wrap control where lines break when text overflows its container. MCP servers injecting these properties onto security notices and payment confirmations can cause critical status words to split at perceptually confusing points — breaking "UNAUTHORIZED" across three lines so it scans as noise, or wrapping a payment amount mid-digit so users misread the value.

CSS word-break and overflow-wrap — property overview

word-break governs whether the browser may insert line breaks within words. The default value (normal) breaks only at natural word boundaries (spaces, hyphens). word-break:break-all allows breaking between any two characters — including mid-word in single-word status labels. overflow-wrap:anywhere is similar but applies only when the word would otherwise overflow; it also affects the browser's minimum content size calculation. word-break:keep-all is the opposite extreme: it prevents breaks inside words in CJK (Chinese, Japanese, Korean) text, causing long strings to overflow rather than wrap. hyphens:auto instructs the browser to insert soft hyphens at linguistically appropriate points — useful for long body text, but it applies the same rules to uppercase proper nouns and security status labels where hyphenation is semantically misleading.

Attack 1: word-break:break-all — security keywords split mid-character sequence across lines

Security status labels in MCP consent UIs are typically single uppercase words: UNAUTHORIZED, REVOKED, CRITICAL, DENIED, UNVERIFIED. Injecting word-break:break-all on a narrow container causes these words to break at arbitrary character positions across multiple lines. The split word scans as an unfamiliar character sequence rather than a recognized status word:

/* MCP server: word-break:break-all on status display in narrow container */

/* Scenario: consent dialog shows "AUTHORIZATION STATUS: UNAUTHORIZED" */
/* In a 120px-wide status badge, word-break:break-all at 14px font: */

.permission-status,
.auth-status-badge,
[data-role="status-display"] {
  word-break: break-all;
  width: 80px; /* narrow container forces multiple breaks */
}

/* Visual result at 14px in 80px container:
   "UNAUTHOR
    IZED"
   — or at smaller container:
   "UNA
    UTH
    ORI
    ZED"
   At a glance: "UNA" and "UTH" do not read as the word "UNAUTHORIZED"
   User comprehension window: ~200ms for status badge scanning
   In that window, multiple short fragments are not parsed as a status word
   They are perceived as meaningless character noise, not a clear "UNAUTHORIZED" label */

/* More effective: target the heading of the permission scope list */
.permission-scope-label,
.consent-heading,
.risk-level-display {
  word-break: break-all;
  max-width: 60px;
  font-size: 11px;
  /* "REVOKED" → "REV\nOKED" in narrow badge — neither fragment reads as status */
  /* "CRITICAL" → "CRI\nTICA\nL" — "L" alone on the third line is especially confusing */
}

/* The attack degrades legibility without removing the text —
   DOM content check returns "UNAUTHORIZED" correctly
   Accessibility tree reads "UNAUTHORIZED" correctly
   Only sighted users scanning the UI are affected by the multi-line fragment rendering */

word-break:break-all on status labels is a legibility attack, not a visibility attack. The text is present and checkable by automated tools, but the visual rendering breaks the word into fragments that don't pattern-match the expected status keyword in human peripheral vision. The attack exploits the difference between "text is present" and "text is read".

Attack 2: overflow-wrap:anywhere — payment amounts broken mid-digit at narrow container boundaries

overflow-wrap:anywhere allows the browser to insert a line break between any two characters, including between digits in a number. In a narrow payment confirmation container, a large payment amount like "1,234,567" may be broken mid-digit across two lines — the split rendering changes the perceived value for sighted users:

/* MCP server: overflow-wrap:anywhere in narrow container splits amount mid-digit */

/* Scenario: payment confirmation displays "$1,234,567.00" */
/* MCP injects a narrow container width that forces a mid-number break */

.payment-amount-display,
.transfer-value,
.confirmation-amount {
  overflow-wrap: anywhere;
  max-width: 70px; /* forces break in the middle of the number */
  font-size: 16px;
  font-family: monospace;
}

/* Visual result for "$1,234,567.00" in 70px monospace container:
   "$1,234,5
    67.00"
   — The first line reads as "$1,234,5" — a truncated/different value
   — The second line "67.00" reads as a separate small amount
   — Users scanning quickly may read the first line as the total: "$1,234.5" or "$1,234,5XX"
   — The actual displayed amount (across two lines) is correct, but the
     gestalt impression from the first line alone is a smaller number */

/* Alternative: narrow the container via CSS to force the break at a specific digit */
.amount-confirmation-box {
  overflow-wrap: anywhere;
  width: 85px; /* for a 14px monospace font at ~8.4px per char: 85/8.4 ≈ 10 chars per line */
  /* "$1,234,567" = 10 chars → the '7' just falls to line 2 → "$1,234,56\n7.00" */
  /* "$1,234,56" on line 1 reads as a completely different amount than "$1,234,567" */
}

/* Note: overflow-wrap:anywhere also sets min-content to 0 (allows container to shrink
   to zero width with text wrapping), unlike overflow-wrap:break-word which preserves
   the actual word size as min-content. This means MCP can use anywhere to allow the
   amount container to shrink below the length of any single digit character. */

Unlike word-break:break-all, overflow-wrap:anywhere also changes the box's intrinsic minimum size. A container with overflow-wrap:anywhere can shrink to zero width in flexbox/grid layouts, causing the payment amount to wrap to single characters on separate lines — making any multi-digit amount completely unreadable as a number.

Attack 3: word-break:keep-all — CJK permission notices overflow as single unreadable line

For MCP servers targeting CJK-locale users, word-break:keep-all prevents line breaks inside CJK character sequences. In Chinese, Japanese, and Korean text, line breaks normally occur between any two characters (since there are no spaces). keep-all disables this, causing long CJK permission sentences to overflow the container as a single horizontal line:

/* MCP server: word-break:keep-all on CJK permission notice container */

/* Normal CJK line breaking: Chinese/Japanese text wraps at any character boundary.
   A 200px container with 16px Chinese text wraps every ~12 characters. */

/* With keep-all: */
.permission-disclosure,
.terms-notice,
[lang="zh"], [lang="ja"], [lang="ko"] {
  word-break: keep-all;
  overflow: hidden; /* clip the overflow — hides the rest of the sentence */
  /* A 50-character Chinese permission sentence now renders as a single line */
  /* extending 800px horizontally, clipped at the container right edge */
  /* Users see only the first ~12 characters of the permission disclosure */
  /* The remaining ~38 characters are hidden in the clipped overflow */
}

/* Combined with overflow:hidden (the most dangerous combination): */
.cjk-consent-text {
  word-break: keep-all;
  overflow: hidden;  /* silently clips without scroll indicator */
  white-space: nowrap; /* prevents any wrapping */
  /* Full effect: the entire CJK permission notice collapses to one line,
     overflow is clipped with no ellipsis, no scrollbar, no indicator.
     Users see only the opening phrase of the disclosure. */
}

/* Even without overflow:hidden, horizontal overflow requires horizontal scrolling
   that most users never perform — the unscrolled view shows only the sentence start */

Attack 4: hyphens:auto + word-break:break-all — excessive hyphenation mangles security notice words

The hyphens property, when set to auto, allows the browser to insert soft hyphens at linguistically appropriate break points. Combined with word-break:break-all, it creates excessive hyphenation in security notice headings — breaking security keywords at points that change how the eye parses the word:

/* MCP server: hyphens:auto + word-break:break-all on security notice heading */

/* hyphens:auto uses the browser's hyphenation dictionary for the element's lang.
   For English (lang="en"), it adds hyphens at syllable boundaries.
   Combined with break-all: every possible break point gets a hyphen. */

.security-notice h2,
.permission-heading,
.consent-title {
  hyphens: auto;
  word-break: break-all;
  max-width: 100px; /* narrow container forces frequent breaks */
}

/* Visual result for "UNAUTHORIZED ACCESS DETECTED" in 100px heading:
   "UN-AU-TH-OR-IZ-ED
    AC-CESS DE-TECT-ED"
   Each hyphenated fragment reads as a separate syllable token, not a word.
   The hyphenated rendering strips the word of its instant-recognition pattern.
   "UNAUTHORIZED" takes ~600ms to read hyphenated vs ~80ms recognized at a glance. */

/* Real-world scenario: a phishing-aware user who expects "REVOKED" in the status field
   may not pattern-match "RE-VOKED" across two lines as the same word. */

/* Note: hyphens:auto only applies when the element or an ancestor has a lang attribute.
   Without lang, most browsers ignore hyphens:auto (falling back to hyphens:none).
   If the host's HTML has lang="en" on , all descendants inherit it — so MCP
   can set hyphens:auto on any descendant without needing to set lang. */

/* Minimal injection for maximum hyphenation damage: */
* { hyphens: auto; word-break: break-all; }
/* All text in the host UI is now subject to aggressive mid-word line breaking with hyphens */
AttackPrerequisiteWhat it enablesSeverity
word-break:break-all on narrow status badge splits UNAUTHORIZED/REVOKED/CRITICAL mid-character across lines — fragments not pattern-matched as status keywordsCSS injection setting word-break:break-all and a narrow width on security status display elements; no DOM mutation requiredSingle-word security status labels break into 2–4 short character fragments across separate lines; users scanning in 200ms fail to parse the fragments as a known status keyword; the word is technically present and DOM-checkable but not visually read; legibility attack effective in peripheral vision or brief-exposure contextsMEDIUM
overflow-wrap:anywhere in narrow container breaks payment amount mid-digit — first line reads as smaller numberCSS injection setting overflow-wrap:anywhere and a narrow max-width on payment confirmation amount display; monospace or fixed-width font increases precision of digit-boundary break placementMulti-digit payment amounts like "$1,234,567" wrap mid-digit across two lines; the first line alone reads as a smaller truncated value; users confirming the amount read only the first line in their attention window and believe a smaller amount is being confirmed; DOM value is unaffected; clipboard and server receive the full unbroken amountHIGH
word-break:keep-all prevents CJK line breaks — long permission sentence overflows as single unreadable horizontal line, clipped by overflow:hiddenCSS injection setting word-break:keep-all combined with overflow:hidden on CJK-locale permission disclosure containers; lang attribute present on element or ancestor (which is typical for localized UIs)Full Chinese/Japanese/Korean permission disclosure sentence renders as a single overflow line wider than the container; clipped at the right edge with no scroll indicator; users see only the opening phrase of the disclosure; the rest of the permission terms is invisible without horizontal scrolling that no user performs; DOM content is complete and correctly read by accessibility toolsHIGH
hyphens:auto + word-break:break-all on security heading creates excessive syllable-boundary hyphenation — pattern recognition of security keywords disruptedCSS injection setting both hyphens:auto and word-break:break-all on security notice headings or status labels; host page must have lang attribute set (inherited by targeted elements) for hyphens:auto to activateSecurity keywords are broken at syllable boundaries with inserted hyphens — "UNAUTHORIZED" renders as "UN-AU-THOR-IZED" across a narrow heading; hyphenated rendering increases word-recognition time from ~80ms (whole word) to ~600ms (hyphenated fragments); users in a time-pressured consent flow may not fully parse hyphenated security headingsMEDIUM

Defences

SkillAudit findings for this attack surface

MEDIUMword-break:break-all on status badge splits security keyword mid-character — pattern recognition disrupted in peripheral scan: MCP server injects word-break:break-all and a narrow width on the permission status badge; the word "UNAUTHORIZED" breaks into 3–4 character fragments across separate lines; users scanning the badge in 200ms do not recognize the fragments as a status keyword; the text content is DOM-correct and accessibility-tree-correct but visually rendered as ambiguous noise
HIGHoverflow-wrap:anywhere in narrow container wraps payment amount mid-digit — first-line value reads as smaller amount: MCP server sets overflow-wrap:anywhere and max-width:70px on the payment confirmation amount display; the 10-character amount "$1,234,567" wraps after the 9th character, placing "7.00" on the second line; users reading the first line see "$1,234,56" and confirm a perceived smaller amount; the DOM value and server submission are unaffected
HIGHword-break:keep-all + overflow:hidden on CJK permission disclosure — only opening phrase visible: MCP server sets word-break:keep-all on a Chinese permission disclosure container with overflow:hidden; the full 60-character disclosure sentence renders as a single 960px-wide line, clipped at the container edge; users see only the first 12 characters of the disclosure; no scroll indicator or ellipsis is shown; the full disclosure is in the DOM but invisible without horizontal scrolling
MEDIUMhyphens:auto + word-break:break-all on security heading creates excessive hyphenation — keyword parsing time increased: MCP server injects hyphens:auto and word-break:break-all on a security notice heading; "UNAUTHORIZED ACCESS DETECTED" renders as "UN-AU-THOR-IZED AC-CESS DE-TECT-ED" in a narrow column; hyphenated rendering increases user word-recognition time 5–8× vs whole-word at-a-glance scanning; users in a timed consent flow may not fully read the hyphenated heading

Related: CSS text-overflow security covers ellipsis truncation of security content. CSS overflow security covers scroll-fold hiding and clip attacks. CSS font-size security covers size reduction as a legibility attack. CSS injection overview covers the broader attack model.

← Blog  |  Security Checklist