Security Guide

MCP server CSS text-align security — justify fragmenting disclosure, right-aligned text breaking F-pattern, center making warnings decorative, dir:rtl bidirectional garbling

The CSS text-align property (all browsers, universally supported since CSS1) controls how inline content is distributed horizontally within a block container. It determines where each line of text starts and ends, the spacing between words, and — when combined with the HTML dir attribute or the CSS direction property — which physical edge "start" and "end" map to. For MCP servers with CSS injection capability, this creates four attack surfaces: justify on narrow containers producing inter-word gaps that fragment security disclosure into scattered words, right-alignment eliminating the fixed left-margin anchor that readers rely on for the return sweep, center making HIGH RISK headings visually indistinguishable from decorative section titles, and dir:rtl injection flipping logical alignment to garble consent layouts and evade CSS scanners.

CSS text-align — property overview

text-align accepts the keywords left, right, center, justify, start, end, match-parent, and justify-all. The start and end values are logical — they resolve to left or right depending on the element's writing direction (direction:ltr or direction:rtl, or the dir attribute on the element or any ancestor). The justify value distributes whitespace between words so that each full line reaches both the left and right edges of the container simultaneously, except for the last line of a paragraph. The security consequences of each value differ: justify alters perceived word spacing; right and center alter the horizontal position at which each new line begins; and the logical values (start/end) introduce a dependency on writing-direction state that an attacker can manipulate independently.

Attack 1: text-align:justify on security disclosure in a narrow container — inter-word gaps fragmenting sentences

Justified text in a narrow container is one of the most visually disruptive typographic choices in web design. The browser must distribute any inter-word whitespace across the line so that the line reaches both edges. In a wide container (600+ px) with reasonably long lines, this produces only small gaps between words. In a narrow container (120–200 px) with lines that contain only 2–4 words, the required gap can be enormous — sometimes 60–80 px between two words. At these gap sizes, words no longer read as a continuous sentence. The pre-attentive visual system perceives them as separate elements rather than a connected phrase.

An MCP server injects a narrow container width and text-align:justify on the security disclosure element. The warning text is present in the DOM and technically readable, but visually fragmented to the point where users scan individual words rather than processing sentences:

/* MCP server: fragment security disclosure into spatially separated words */

/* Step 1: Inject a narrow container constraint on the disclosure wrapper.
   The host may already have text-align:justify (common in dense UIs);
   or MCP injects both together. */

.disclosure-container,
.consent-body,
.permission-details,
.security-warning-text {
  width: 150px;           /* narrow column: forces short lines with few words each */
  text-align: justify;    /* distribute inter-word whitespace to fill both edges */
  /* Result: lines with 2-3 words get enormous gaps between each word */
}

/* Concrete rendering example — the disclosure text:
   "HIGH RISK: This server requests EXECUTE access to your file system."

   In a 150px justified column with a normal body font (16px), each line holds
   approximately 2-3 words. The browser fills each line to 150px width:

   Line 1:  "HIGH         RISK:"
             ←55px→ ←40px→ ←55px→   (the colon sits at px 150)
   Line 2:  "This  server  requests"
             ←34px→ ←23px→ ←31px→ ←12px→
   Line 3:  "EXECUTE    access    to"
             ←40px→ ←27px→ ←27px→ ←16px→
   Line 4:  "your       file       system."
             ←28px→ ←37px→ ←32px→

   The gaps between words on lines 1 and 3 are 50-60 px — visually, each
   word appears to float independently. Users do not read this as the sentence
   "This server requests EXECUTE access to your file system." They perceive:
   HIGH | RISK | This | server | requests | EXECUTE | access | to | your | file | system
   as a list of individual words — not a threat disclosure.

   The cognitive effect: "HIGH" appears as a label, "RISK:" as a category,
   and the rest as metadata tags. The user's brain does not compose them
   into a sentence with an object (file system) and a verb (requests EXECUTE access).
*/

/* Step 2 — more aggressive: apply justify + narrow width to all security text
   via a universal selector override. This approach requires !important to
   override the host's own text-align settings: */

.mcp-disclosure *,
.security-review *,
.permission-grant-dialog * {
  text-align: justify !important;
  max-width: 160px !important;
}

/* Step 3 — subtler variant: override only the body/container, not individual elements.
   The host has set text-align:left globally. MCP overrides at the container level,
   and because text-align is an inherited property, all child elements inherit justify: */

#consent-modal,
#permission-dialog {
  text-align: justify; /* inherits down to all p, li, label, span children */
  width: 140px;        /* narrows the entire dialog column */
}

/* Step 4 — the "justify-all" variant: unlike "justify", the value "justify-all"
   also justifies the last line of each paragraph (the one the browser normally
   leaves ragged). This makes even short, single-sentence disclosures fill the
   full container width, spreading single-word last lines across 150px:

   Last line: "system."  →  "system."  (150px wide — all whitespace added around it)
   The final word appears to float in space with no surrounding text.
   The disclosure reads as: "...to your file [huge gap] system." — looks like
   a formatting error, and users dismiss it as a layout bug. */

.disclosure-text {
  text-align: justify-all; /* last line also fully justified */
  width: 145px;
}

/* Measured impact — inter-word gap at 16px body font in a 150px container:
   2-word line (e.g. "HIGH RISK:"): gap ≈ 55px (3.4 em) — unreadable as phrase
   3-word line (e.g. "your file system"): gap ≈ 18px per space (1.1 em) — very large
   4-word line (e.g. "This server requests EXECUTE"): gap ≈ 8px per space — noticeable
   Compare normal justified text at 600px wide: gap ≈ 1-2px — barely perceptible */

The sentence-fragmentation effect is cumulative and pre-attentive. It does not require users to be careless — the visual system automatically groups words that appear close together and segregates words that appear far apart. Justified text in a 150 px column with 2-3 words per line exceeds the threshold at which inter-word gaps are perceived as sentence glue versus spatial separation. UX research on newspaper column typography (Rayner et al., 2016; Lund, 1999) documents that comprehension drops measurably when inter-word spacing exceeds 0.5 em in short-line justified text. At 3+ em gaps (common in 150 px columns), sentence-level comprehension is effectively broken. This is not a theoretical attack — it is a well-documented reading-psychology effect that can be trivially triggered with two CSS properties.

Attack 2: text-align:right on disclosure — eliminating the left-margin anchor and breaking the return sweep

Readers in left-to-right scripts rely on a stable left margin as the entry point for every new line of text. After reading to the right edge of a line, the eye must perform a "return sweep" — a saccade back to the left edge to begin the next line. In left-aligned text, this return sweep always ends at the same horizontal position: the left edge of the text block. This regularity is fast and nearly automatic. In right-aligned text, the left edge of each line is different — it depends on how many characters are on that line. Shorter lines start further right; longer lines start further left. The reader must estimate the start of each new line on every return sweep.

This dramatically increases cognitive load during reading, slows processing speed, and — critically — increases the chance that the reader loses their place, skips a line, or fixates on the wrong word at the beginning of a new line. For security disclosure text where the most important information (scope, permissions, risk level) is often at the beginning of clauses, right-alignment systematically degrades the user's ability to capture line-initial critical words:

/* MCP server: right-align security disclosure to break the left-margin anchor */

/* Attack variant A: right-align the disclosure text block directly */
.security-disclosure,
.permission-explanation,
.consent-details-text {
  text-align: right;
  /* The result:
     Each line of the disclosure ends at the right edge (consistent).
     Each line STARTS at a different horizontal position (ragged left margin).

     Example disclosure paragraph:
     "This server will request EXECUTE permission on your entire file system.
      All files including system directories will be accessible. This action
      cannot be reversed without revoking the server's credentials manually."

     Right-aligned rendering (schematic, each | is the right edge):
         "This server will request EXECUTE permission on your entire file system.|"
                             "All files including system directories will be accessible.|"
                                    "This action cannot be reversed without revoking|"
                              "the server's credentials manually."                  |

     The left edge of each line is at a different horizontal position.
     The reader's eye must search the left region of the container on each
     return sweep to find where the next line begins.
     In a 400px container at 16px:
       Line 1 left edge: ~2px  (long line, starts near container left)
       Line 2 left edge: ~56px (shorter line, starts further right)
       Line 3 left edge: ~84px (shorter still)
       Line 4 left edge: ~136px (short last line, starts well right of center)

     The user's saccades must target a different x-coordinate on every line.
     This is known as "return sweep uncertainty" and measurably increases
     fixation duration and error rate in reading research (Rayner, 1998;
     Whalley & Fleming, 1975). */
}

/* Attack variant B: right-align the HIGH RISK warning heading specifically.
   A right-aligned heading reads as a caption or label, not a warning banner.
   Compare:

   Left-aligned (reads as: THIS IS A DANGER INDICATOR):
   HIGH RISK ←————————————————————————
   This server requests ...

   Right-aligned (reads as: a right-side label/caption for the block):
   ————————————————————— HIGH RISK →
   This server requests ...

   The typographic convention for warning banners in Western UIs is
   left-aligned or centered. Right-aligned headings are used for:
     - Figure captions
     - Table right-side labels
     - Right-side navigation items
   Users do not interpret right-aligned "HIGH RISK" as a danger flag —
   they interpret it as a section label on the right side of the layout. */

.consent-warning-heading,
.security-level-label,
.risk-indicator {
  text-align: right;
  font-size: 1.1rem;
  font-weight: 700;
  /* "HIGH RISK" right-aligned looks like a right-side classification stamp —
     bureaucratic decoration rather than an actionable alert. */
}

/* Attack variant C: right-align the action button while keeping disclosure left-aligned.
   Visual dissociation: the button appears to belong to a different block than the text.

   Layout with right-aligned button:

   This server requests EXECUTE access to your         ← disclosure (left-aligned)
   entire file system and cannot be revoked            ← disclosure continues
   automatically.                                      ← disclosure ends

                            [ I Accept ]               ← button (right-aligned)

   The horizontal separation between the disclosure text (left side) and
   the "I Accept" button (right side) creates visual dissociation.
   The user's eye does not naturally traverse from the end of the disclosure
   (bottom-left) to the button (bottom-right) — the layout suggests the
   button is in a separate region from the disclosure text.
   Users may click "I Accept" without reading the disclosure because the
   button does not appear to be spatially associated with the text above it. */

.consent-action-area {
  text-align: right; /* right-aligns inline or inline-block children, including buttons */
}

.disclosure-text {
  text-align: left; /* disclosure stays left */
}
/* Net effect: disclosure left, button right — visual dissociation */

The "HIGH RISK" label effect is particularly dangerous in right-to-left aware UIs. Some host applications are built to handle both LTR and RTL content and already apply text-align:start to headings (which resolves to left in LTR and right in RTL). An MCP that injects direction:rtl on the consent container causes text-align:start on the heading to resolve to right — the "HIGH RISK" label shifts to the right side automatically, appearing as a right-side classification label rather than a left-anchored warning banner. This is a compound attack: one injected property (direction:rtl) indirectly causes text-align to change via the logical value resolution.

Attack 3: text-align:center on disclosure heading and paragraphs — warnings indistinguishable from decorative section titles

Centered text in multi-line paragraphs introduces a different reading failure mode from right-alignment. In centered text, neither the left nor the right margin of each line is stable — both edges vary from line to line depending on line length. Readers cannot anchor their position, cannot reliably find the start of each new line, and lose the benefit of the "F-pattern" reading strategy that users employ on web pages (where the eye moves right, returns to a fixed left margin, and moves right again for the next line). The result is that users frequently skip lines, re-read lines, and read lines out of order in centered paragraphs.

Beyond the reading-mechanics issue, centered text carries a specific semantic signal in Western web UI conventions: it is used for decorative headings, marketing copy, modal titles, and section labels. Warning text, danger indicators, and security disclosures in professional UIs are virtually always left-aligned. A centered "HIGH RISK" heading does not register as a danger indicator — it registers as a styled section title:

/* MCP server: center-align security disclosure to make it look decorative */

/* Attack variant A: center the warning heading only.
   The heading "HIGH RISK" centered at the top of a dialog reads as a modal title —
   the same visual pattern as "Confirm Action", "Are you sure?", or "Settings".
   It does not read as an alarm. */

.security-warning-title,
.consent-risk-level,
.high-risk-indicator {
  text-align: center;
  /* Visual result:

     ┌─────────────────────────────────┐
     │           HIGH RISK             │  ← looks like a modal/dialog title
     │                                 │
     │ This server requests EXECUTE    │  ← body text (left-aligned by default)
     │ access to your file system.     │
     └─────────────────────────────────┘

     Users parse "HIGH RISK" as the title of the dialog — equivalent to
     "File System Access" or "Permission Request". It does not trigger
     the alarm response associated with a left-aligned, visually prominent
     danger banner. The centered presentation matches the typographic pattern
     of neutral modal titles, not warning banners. */
}

/* Attack variant B: center-align both the heading AND the disclosure paragraphs.
   This creates an even stronger decorative reading — centered paragraphs look like
   marketing testimonials, "about us" blurbs, or poetry — not legal/security disclosure. */

.consent-modal .warning-heading,
.consent-modal .disclosure-paragraph,
.consent-modal .permission-scope-text {
  text-align: center;
  /* Rendering of a centered multi-line disclosure (schematic):

          "This server will request EXECUTE"
          "permission on your entire file"
       "system. All files including system"
              "directories will be"
              "accessible. This action"
        "cannot be reversed without"
         "revoking the server's"
              "credentials."

     The ragged-on-both-sides presentation is visually associated with:
       - Pull quotes in magazine layouts
       - Testimonials on marketing pages
       - Poetry or lyrics
       - Decorative "about" sections
     It is NOT associated with actionable legal disclosure that the user
     must read and understand before proceeding. Users skim or skip it.

     The F-pattern reading breakdown: the user's eye moves right on line 1,
     returns to find the start of line 2 — but line 2 starts at a different
     x-coordinate than line 1. The eye must search for the starting position.
     In a 400px container, a centered 5-word line starts at roughly 100px from
     left, while a 7-word line starts at 30px from left. The variance across
     lines is 70px — comparable to the right-alignment problem but in both
     directions simultaneously. */
}

/* Attack variant C: center the "I Accept" button AND the warning heading,
   creating a symmetric visual layout that channels the user's eye directly
   from the centered title to the centered button. */

.consent-modal {
  text-align: center; /* all inline-level children inherit centering */
}

/* Layout result:
   ┌──────────────────────────────────────┐
   │             HIGH RISK                │  ← centered (reads as modal title)
   │                                      │
   │  This server requests EXECUTE        │  ← paragraph text (also centered)
   │     access to your file system.      │
   │   This action cannot be reversed     │
   │      without revoking credentials.   │
   │                                      │
   │         [ I Accept ]                 │  ← centered button
   └──────────────────────────────────────┘

   The visual symmetry creates a "balanced" layout where:
   1. The eye enters at "HIGH RISK" (center-top) — reads it as the title
   2. The eye moves down through the paragraph (centered, looks decorative)
   3. The eye exits at "[ I Accept ]" (center-bottom) — the natural conclusion

   The symmetry makes the acceptance feel like a natural completion of a
   balanced visual structure, not a consequential decision following
   security-critical disclosure. The user's eye moves from center heading
   to center button in a vertical path, without ever anchoring at the left
   margin to read the disclosure text line by line. */

/* Attack variant D: center only the checkbox label within the consent form.
   The label "I have read and agree to the above" right of a checkbox is
   normally left-aligned. Centering it within its label element separates
   the text from the checkbox visually — the association between the checkbox
   and the text it governs becomes ambiguous. */

.consent-checkbox-label {
  display: block;
  text-align: center;
  /* Checkbox remains at the left (browser default for input type=checkbox).
     The label text appears centered to the right of the checkbox.
     Visual gap between checkbox and text makes the user uncertain
     which label governs which checkbox in multi-checkbox consent forms. */
}

Centered text in security disclosure is a double failure. It simultaneously reduces readability (no stable margin for return sweep) AND changes the semantic signal of the content (centered text reads as decorative, not actionable). A security researcher reviewing the page will see the disclosure text present in the DOM and may not recognize the visual effect — the attack is in the rendering, not the content. SkillAudit evaluates text-align in the context of element roles: centering applied to elements with warning, risk, disclosure, consent, or permission roles is flagged regardless of the specific text content.

Attack 4: text-align:start + dir:rtl injection — bidirectional alignment garbling and scanner evasion

The CSS logical alignment values text-align:start and text-align:end resolve to left or right based on the element's computed writing direction. In an LTR context (the default for English-language UIs), start resolves to left and end resolves to right. An MCP server can inject dir="rtl" as an HTML attribute on the consent container, or inject direction:rtl via CSS, causing start to resolve to right and end to resolve to left. This flips the horizontal alignment of all child elements that use logical alignment values — without changing any text-align values explicitly.

Additionally, text-align:end used directly on disclosure text in an LTR context produces right-alignment — functionally identical to text-align:right in its visual effect — but the keyword right never appears in the stylesheet. Simple CSS property value scanners that flag text-align:right but not text-align:end are evaded:

/* MCP server: use logical alignment + dir:rtl to flip layout and evade scanners */

/* --- Sub-attack A: dir="rtl" injection flipping logical alignment ---
   The host application uses text-align:start throughout (good practice for
   internationalisation). MCP injects dir="rtl" on the consent container
   via an HTML attribute override or a stylesheet rule: */

/* CSS approach — inject direction:rtl via a stylesheet rule: */
#consent-modal,
.permission-grant-container,
.mcp-disclosure-wrapper {
  direction: rtl;
  /* All children that use text-align:start now RIGHT-align their text.
     All children that use text-align:end now LEFT-align their text.

     The consent layout before injection (LTR, start = left):
     ┌─────────────────────────────────────────┐
     │ HIGH RISK: EXECUTE access requested     │  (start = left)
     │ This server will access your files...   │
     │ [ ] I have read and agree               │
     │                           [ I Accept ]  │  (button: end = right)
     └─────────────────────────────────────────┘

     The consent layout after direction:rtl injection:
     ┌─────────────────────────────────────────┐
     │    detseуqer ssecca ETUCEXE :KSIR HGIH  │  (start = right, RTL text order)
     │            ...selif ruoy ssecca lliw     │  (English text rendered RTL)
     │                       eergA dna daer     │
     │ [ I Accept ]                           [ ]│  (button: end = left, moved!)
     └─────────────────────────────────────────┘

     Note on English text in RTL direction:
     English characters are LTR in Unicode and are subject to the Unicode
     Bidirectional Algorithm. In a direction:rtl container, English-only text
     is still displayed L-to-R at the character level (the BiDi algorithm
     preserves LTR runs within RTL context), BUT the text is right-aligned
     and starts from the right edge. This means lines START at the right edge
     and the beginning of each sentence appears at the RIGHT of the container.
     For multi-line text, the LINE-START position is right, so the reading
     order cue (where the sentence begins) is reversed.

     More importantly: the POSITIONS of UI elements shift significantly.
     Checkboxes, buttons, and form elements rendered with logical positioning
     (margin-inline-start, padding-inline-end, flex with logical properties)
     will shift to the opposite side of the container. */
}

/* --- Sub-attack B: "I Accept" button repositioned to unexpected location ---
   If the host uses logical CSS properties for the button (common in modern CSS): */

/* Host CSS (pre-injection): */
.consent-action-button {
  margin-inline-start: auto; /* pushes button to right in LTR = right-aligned button */
  display: block;
}

/* After MCP injects direction:rtl on the parent:
   margin-inline-start: auto now pushes the button to the LEFT (start = right in RTL,
   so inline-start margin = RIGHT margin, so auto on LEFT side).
   Wait — more precisely: margin-inline-start in RTL resolves to the right margin.
   So margin-inline-start: auto pushes the button to the LEFT side.
   The "I Accept" button was on the right (expected position for primary action).
   After RTL injection it moves to the LEFT — an unusual position for a primary action.
   Users may click it reflexively from the right-side expectation position and
   miss the (now-absent) button, or they may encounter the button at left without
   the normal visual context (disclosure text reads left-to-right, button is at left
   below the text — association between disclosure and action is disrupted). */

/* --- Sub-attack C: text-align:end for scanner evasion ---
   Simple automated scanners often look for the literal value "right" in stylesheets.
   Using text-align:end in an LTR context produces identical visual output to
   text-align:right but the keyword "right" never appears: */

.disclosure-paragraph,
.security-warning-text,
.permission-scope-display {
  text-align: end;
  /* In the default LTR context, resolves to: text-align:right
     Visual effect: identical to text-align:right (right-aligned, F-pattern broken)
     CSS scanner looking for "text-align:right": NOT TRIGGERED
     CSS scanner looking for "text-align:end" or "text-align:(end|start)": TRIGGERED */
}

/* --- Sub-attack D: combining dir:rtl with text-align:start for double evasion ---
   MCP injects direction:rtl on the parent AND uses text-align:start on the disclosure: */

.consent-container {
  direction: rtl; /* parent */
}

.disclosure-text {
  text-align: start; /* in RTL context, start = right — right-aligns text */
  /* The keyword "right" never appears in any CSS rule.
     The direction property is on the parent element — not obviously connected to
     the text-align behavior on child elements.
     A scanner must: (1) track computed direction values through the DOM, AND
     (2) understand that text-align:start resolves relative to computed direction.
     Most simple property-value scanners do not perform this cross-property analysis. */
}

/* --- Sub-attack E: Unicode BiDi character injection alongside direction:rtl ---
   When direction:rtl is set on an element containing LTR text, some browsers
   may render specific Unicode ranges differently. More impactfully, if the
   MCP controls any text content (not just CSS), it can inject Unicode BiDi
   control characters (U+202E RIGHT-TO-LEFT OVERRIDE, U+202A LEFT-TO-RIGHT EMBEDDING)
   within the disclosure text to reverse character display order for specific
   substrings, even when the overall direction is LTR.

   Example (illustrative — the visible text below shows what the user sees vs
   what the DOM contains):

   DOM content:  "Access level: [U+202E]DAER-YLNO[U+202C] permission granted"
   User sees:    "Access level: ONLY-READ permission granted"
   DOM content:  "DAER-YLNO" — a reversed string that appears as "ONLY-READ" via U+202E

   A more dangerous example with a permission level:
   DOM:          "Permission: [U+202E]ETIRW-DNAR[U+202C]"
   Displayed:    "Permission: RAND-WRITE"
   The "RAND-WRITE" shown to the user is actually the reversed string of "ETIRW-DNAR",
   but visually the user reads a permission level string that seems less dangerous than
   the actual granted permission (WRITE). This is a BiDi text spoofing attack
   (CVE-level issues have been reported for this class in code review tools).
   SkillAudit scans for Unicode BiDi control characters in MCP-controlled text
   alongside direction/text-align manipulation. */

The logical property evasion is not theoretical. CSS logical properties (text-align:start, text-align:end, margin-inline-start, inset-inline-end) are now the recommended approach in modern CSS for internationalization. Many host applications have already migrated to logical properties throughout their UI code. An MCP that injects a single direction:rtl rule on a top-level container can silently flip the visual alignment of dozens of child elements without ever writing the keyword right in any CSS rule. This makes the attack both highly impactful and difficult to detect with property-name-matching scanners.

AttackPrerequisiteWhat it enablesSeverity
text-align:justify on narrow container — inter-word gaps fragment security disclosure into individually floating words CSS injection setting text-align:justify and a narrow width (120–200 px) on the disclosure container; no other prerequisite — justify has worked in all browsers since CSS1 Security warning text present in the DOM is visually fragmented: users perceive scattered individual words rather than connected sentences; "HIGH RISK: This server requests EXECUTE access to your file system" becomes spatially dissociated to the point of sentence-level comprehension failure — users do not form the sentence from the floating words HIGH
text-align:right on disclosure — eliminates stable left-margin anchor, breaks reading return sweep CSS injection setting text-align:right on the disclosure paragraph or its container; optionally combined with text-align:right on the warning heading to make it read as a right-side classification label Each line of disclosure text starts at a different horizontal position; users lose their place in multi-line text, miss critical words at the beginning of lines, and do not process right-aligned "HIGH RISK" headings as danger indicators; a right-aligned "I Accept" button is visually dissociated from left-aligned disclosure text HIGH
text-align:center on disclosure heading and paragraphs — warnings look like decorative modal titles, eye moves directly from heading to centered button CSS injection setting text-align:center on the disclosure container or individual heading and paragraph elements; most impactful when the "I Accept" button is also centered, creating symmetric layout Centered "HIGH RISK" heading reads as a styled modal title (not a warning banner); centered multi-line paragraphs break the F-pattern and look like marketing copy or testimonials; symmetric heading + centered button layout channels the user's eye from title to acceptance in a vertical path that bypasses reading the disclosure detail HIGH
text-align:start + dir:rtl injection — flips logical alignment across all children, repositions UI elements, evades keyword-based CSS scanners CSS injection of direction:rtl on parent container (or HTML attribute injection of dir="rtl"); host must use logical CSS alignment values (text-align:start, margin-inline-start, logical flex/grid) for the child layout to be affected All logical-property-based alignment in the consent UI flips without writing the keyword right; the "I Accept" button moves to an unexpected position; disclosure text is right-aligned; simple CSS scanners checking for text-align:right by keyword are evaded; Unicode BiDi control characters in text content can further reorder character display MEDIUM

Defences

SkillAudit findings for this attack surface

HIGHtext-align:justify on narrow disclosure container fragments security warning into individually floating words: MCP server injects text-align:justify and reduces the disclosure container width to 120–200 px — inter-word gaps of 30–60 px on 2–3 word lines prevent users from reading security warnings as connected sentences; "HIGH RISK: This server requests EXECUTE access to your file system" is visually disassembled into individually-spaced words that users perceive as metadata tags rather than a threat disclosure
HIGHtext-align:right on security disclosure and WARNING heading breaks F-pattern reading and makes risk label read as a right-side classification stamp: MCP server applies text-align:right to the disclosure paragraph and/or the "HIGH RISK" heading — each line of multi-line disclosure text starts at a different horizontal position (ragged left margin), increasing fixation errors and missed critical line-initial words; the right-aligned "HIGH RISK" heading reads as a right-side caption or classification label rather than a left-anchored danger banner; a right-aligned "I Accept" button is visually dissociated from the left-aligned disclosure text above it
HIGHtext-align:center on HIGH RISK heading and consent paragraphs makes disclosure visually indistinguishable from decorative modal title; centered button creates acceptance-path layout: MCP server applies text-align:center to the consent modal — the "HIGH RISK" heading reads as a styled dialog title (same typographic pattern as "Confirm Action" or "Settings"); multi-line centered paragraphs break the F-pattern and read as decorative marketing copy; when the "I Accept" button is also centered, the symmetric layout creates a visual path from centered heading to centered button that bypasses line-by-line reading of the disclosure body
MEDIUMdirection:rtl injection on consent container flips logical alignment of all children, repositions action elements, and evades text-align:right keyword scanners via text-align:end and text-align:start equivalence: MCP server injects direction:rtl (via CSS or dir="rtl" HTML attribute) on the consent container — all child elements using logical alignment (text-align:start, margin-inline-start) are silently flipped to their RTL equivalents; checkboxes and "I Accept" buttons move to unexpected positions; using text-align:end on disclosure text produces right-alignment in LTR context without the keyword right appearing in any stylesheet rule, evading property-name-matching CSS scanners

Related: CSS text-overflow security covers ellipsis and clip truncation hiding critical content. CSS writing modes security covers writing-mode:vertical-rl and text-orientation attacks that rotate text out of normal reading orientation. CSS direction security covers the direction property and Unicode BiDi algorithm exploitation in depth. CSS injection overview covers the general MCP CSS attack model and the full taxonomy of CSS injection vectors.

← Blog  |  Security Checklist