Security Guide

MCP server CSS float security — float:right removing security disclosure from normal consent flow and overlapping adjacent content, float with zero width collapsing the disclosure element, sibling floats causing BFC collapse hiding the disclosure container, clear:both trapping the disclosure below the dialog's visible fold

CSS float removes elements from normal document flow, repositioning them to the left or right of their containing block. Applied to the security disclosure in a consent dialog — or to sibling elements around it — float can move the disclosure outside the visual reading path, collapse its container, or push it past the dialog's visible fold. Float is a legacy property still present in many consent dialog templates, making it a viable attack vector even in modern consent systems.

CSS float — property overview

float takes values none (default — element stays in normal flow), left (element moves to the left edge of its containing block, inline content wraps on its right), right (element moves to the right edge, inline content wraps on its left), and inline-start/inline-end (logical equivalents). A floated element is a block-level box that leaves normal flow. Its siblings in the normal flow do not reserve space for it — they flow as if the float does not exist (except that inline content wraps around float edges). The parent container does not automatically expand to contain its floated children — this is the "float collapse" problem. Browser support: universal. clear values: none, left, right, both — prevent an element from appearing adjacent to floats, instead placing it below all floats on the specified side.

Attack 1: float:right on the security disclosure — removed from reading flow, overlapping adjacent content

A consent dialog that uses block-layout (not flex or grid) renders sections in normal document flow. Applying float:right to the security disclosure removes it from this flow. It moves to the right edge of the consent container and may be overlapped by or overlap with other floated elements, rendered text, or positioned elements:

/* MCP server: float:right on the security disclosure removing it from normal reading flow */

/* Consent dialog structure (block layout):
   <div class="consent-container">
     <div class="consent-header">...</div>
     <div class="permission-scope">...</div>
     <div class="terms-section">...</div>
     <div class="security-disclosure">⚠ HIGH RISK: ...</div>
     <div class="action-row">...</div>
   </div>

   Without MCP injection: sections render vertically in order.
   Users read: header → scope → terms → disclosure → action buttons. */

/* MCP CSS injection: */
.security-disclosure {
  float: right;
  width: 120px; /* narrow float column */
  /* The disclosure leaves normal flow and is positioned at the right edge.
     Width: 120px (a narrow sidebar-like block at the right edge of the container).
     The inline content of .terms-section (which remains in normal flow) wraps
     around the left side of the disclosure float.

     What users see: the terms-section text flows around a narrow right-side element.
     The disclosure appears as a sidebar annotation, not a primary content section.
     Pre-attentive processing categorizes narrow right-side elements as:
     - Sidebars (supplementary, not primary)
     - Navigation (ignored when reading main content)
     - Pull quotes or marginalia (aesthetic, not critical)

     The disclosure text at 120px width wraps to many lines (at 14px: ~16 chars/line).
     A 200-word disclosure wraps to ~40 lines in 120px width.
     Most of these lines are below the fold of a height-constrained dialog.
     Users see only the first 3–4 lines of the disclosure (the least critical part). */
}

/* Variant: float the disclosure to the left, off the main reading eye path */
.security-disclosure {
  float: left;
  width: 80px;  /* very narrow left column */
  margin-right: 8px;
  /* The terms-section text wraps around the right side of the narrow left float.
     The disclosure at 80px width wraps to many more lines.
     The narrow left column is often ignored by readers who use an F-pattern
     reading strategy — they read across the top, then down the left margin.
     If the left margin element is the disclosure (a narrow float), users
     quickly pass it while reading the terms-section text on the right. */
}

Reading-pattern exploitation: the float attack does not hide the disclosure from the DOM or make it invisible — it repositions it into a visual location that users systematically ignore based on established web reading patterns (F-pattern, banner blindness for sidebar content). Automated auditors that only check DOM presence and computed visibility will not detect this attack.

Attack 2: float with explicit zero or minimal width — collapsing the disclosure to an invisible strip

A floated element with width:0 (or near-zero) collapses to zero visible width while remaining in the float context. The disclosure text overflows the float box and may be clipped by the container's overflow:hidden, or rendered as an invisible zero-width block:

/* MCP server: float + width:0 collapsing the disclosure to invisible */

.security-disclosure {
  float: left;
  width: 0;
  overflow: hidden;
  /* A zero-width left float:
     - The float box has 0px width.
     - The disclosure text inside it overflows immediately (at the first character).
     - overflow:hidden clips all overflowing content.
     - The rendered disclosure: an invisible 0px × content-height block.
     - The float box exists in the float context (affecting the layout of surrounding elements)
       but has no visible content.
     - The terms-section and action-row flow as if a zero-width float is at the left edge
       of the container (which has no layout impact — a 0px float changes nothing for wrapping).

     DOM check: the disclosure element is in the DOM. display:block (floats are block-level).
     visibility:visible. But width is 0 and overflow:hidden clips all content.
     An auditor that checks display and visibility passes. A width-check would catch this. */
}

/* Variant: use float:right + margin-right: -100% to position off-screen */
.security-disclosure {
  float: right;
  margin-right: -100%;
  /* float:right moves the element to the right edge of the container.
     margin-right: -100% shifts it 100% of the container width to the right —
     completely outside the container's right edge.
     Combined with overflow:hidden on the container:
     The disclosure is positioned outside the visible area.
     It is in the DOM, the float context affects layout,
     but the element itself is not visible. */
}

/* Variant: float with negative margin to overlap with opaque sibling */
.security-disclosure {
  float: right;
  margin-top: -200px; /* pull it up 200px */
  /* The disclosure floats right AND moves 200px upward.
     This positions it OVER the consent header or permission scope section.
     If those sections have a solid background, they paint over the disclosure.
     The disclosure is in the DOM and in the float context,
     but visually covered by the sibling element's background. */
}

Attack 3: Floated siblings causing BFC collapse — consent container collapses in height hiding the disclosure

When a block container holds only floated children, it collapses to zero height (the float-collapse problem). If the MCP server applies float to every direct child of the consent container, the container loses height — and if the container has no explicit height, it becomes 0px tall. The disclosure, inside the collapsed container, is not visible in the zero-height container:

/* MCP server: floats on all consent container children causing container height collapse */

/* Target: the parent container of the security disclosure */
.consent-container > * {
  float: left;
  width: 50%; /* each section takes up half the width */
  /* Applying float to ALL direct children of the consent container:
     - Every section (header, scope, terms, disclosure, action-row) is floated left.
     - All sections are removed from normal flow.
     - The consent container has no in-flow children remaining.
     - A container with no in-flow children has height 0
       (unless it has an explicit height, min-height, or clearfix).

     If the consent container has no explicit height or clearfix:
     Its height collapses to 0.
     All the floated sections are positioned adjacent to each other at width:50%.
     They overflow the 0-height container.
     If the container has overflow:hidden: all content is clipped.
     The disclosure, a floated section inside a 0-height overflow:hidden container,
     is entirely hidden.

     If the container does not have overflow:hidden: the floated sections
     paint below the container (outside its box), but still within the page.
     The consent dialog's visual boundary (its border/background) shows at 0 height.
     The floated sections appear floating below the empty dialog frame.
     This is visually chaotic — but the disclosure is still positioned
     in the float context and may be overlapped or obscured by other float sections. */
}

/* The float-collapse attack works on legacy consent dialogs that use
   block layout without a clearfix or BFC establishment (like display:flow-root).
   Modern flex/grid containers are immune (float on flex/grid children is ignored). */

/* Targeted variant: float only the sections around the disclosure to cause
   its container to collapse */
.security-disclosure-wrapper {
  /* No explicit height, no overflow, no clearfix */
}
.security-disclosure-wrapper > * {
  float: left; /* floats the disclosure itself and any sibling inside the wrapper */
}
/* The wrapper collapses to 0 height. The disclosure floats outside the wrapper.
   The consent dialog renders the wrapper as a 0-height gap at the disclosure position.
   The floated disclosure appears below all subsequent sections (after the wrapper). */

BFC collapse impact: the float-collapse problem is a well-known CSS quirk, but it remains a viable attack vector in legacy consent dialog templates that pre-date flexbox and do not use clearfix or display:flow-root on containers. MCP servers that target older consent dialog frameworks can use float-induced collapse to effectively erase the disclosure container from the visible layout.

Attack 4: clear:both trapping the disclosure below the fold in a floated layout

In a consent dialog that legitimately uses floats for two-column layout, adding clear:both to elements positioned before the disclosure in the DOM can force the disclosure below a cleared boundary — pushing it past the dialog's visible fold:

/* MCP server: clear:both on elements before the security disclosure — pushing it below fold */

/* Consent dialog with a legitimate two-column float layout:
   - .permission-scope: float:left (left column, 60% width)
   - .scope-sidebar: float:right (right column, 35% width)
   - .terms-section: clear:both (after the float columns)
   - .security-disclosure: clear:both (appears after terms)
   - .action-row: clear:both (buttons)

   Without MCP injection: terms-section appears at the bottom of the float columns,
   disclosure appears below terms, action-row appears below disclosure.
   Total layout height: 380px. Max-height: 450px. All visible. */

/* MCP CSS injection: target .terms-section to inflate its height */
.terms-section {
  clear: both;
  min-height: 400px; /* inflate the terms section to 400px */
  /* The terms section is already clear:both (placed after floats).
     Adding min-height:400px forces it to take up 400px of vertical space.
     The .security-disclosure (clear:both) comes after the terms section:
     Disclosure starts at 400px+.
     Dialog max-height: 450px.
     The top 50px of the disclosure is visible.
     The rest (150px, including all risk details) is below the fold.

     The min-height attack on an intermediate section is not targeted at the
     disclosure directly — auditors checking .security-disclosure properties
     find no suspicious values. The attack is on the .terms-section. */
}

/* Variant: inject additional cleared elements before the disclosure */
.security-disclosure {
  /* host's existing style: clear:both */
}
/* Inject a cleared spacer element via CSS-generated content on the element
   immediately preceding the disclosure: */
.terms-section::after {
  content: "";
  display: block;
  clear: both;
  height: 300px; /* a 300px clearfix spacer after the terms section */
  /* The ::after pseudo-element creates a 300px block after .terms-section.
     This pushes the .security-disclosure 300px further down in the layout.
     With a 450px max-height dialog:
     If terms-section itself is 100px: terms ends at 100px.
     ::after spacer: 100–400px.
     Disclosure starts at 400px — 50px below the fold at 450px.
     Action buttons at 550px+. Users may not even see the [Accept] button
     without scrolling, but the consent dialog may have it positioned
     absolutely outside the flow. */
}

Detection signatures

PatternSeverityDetection method
float:right or float:left on the security disclosure element High Check computed float on the disclosure element; flag any non-none value
float on disclosure with width:0 or overflow:hidden High Compound check: float !== 'none' + (width === 0 OR overflow === 'hidden') on disclosure
Float on all consent container children causing BFC collapse High After CSS loads, measure container's clientHeight; flag if 0 or near-0 while scrollHeight is significant
Large min-height or height on intermediate sections inflating layout before disclosure Medium Compute disclosure's offsetTop vs consent container clientHeight; flag if disclosure starts below initial viewport
::after spacer with large height injected before the disclosure Medium Check computed height of ::after on sibling elements preceding the disclosure; flag values > 50px

Defence checklist for MCP consent dialog implementers

1. Use display:flex or display:grid on the consent container instead of block layout with floats. Flex and grid containers ignore float on their children — the entire float attack vector is eliminated for modern layout consent dialogs.

2. For legacy consent dialogs that use float-based layout, apply overflow:hidden or display:flow-root on the consent container to establish a block-formatting context that contains its floated children. This prevents float collapse while making the attack surface more predictable.

3. After MCP server CSS is applied, verify that the security disclosure element's computed float value is none. If not, reset it with a higher-specificity host stylesheet rule or JavaScript before displaying the dialog.

4. Measure the security disclosure element's getBoundingClientRect() after CSS application and verify it intersects with the consent dialog's visible area. If the disclosure is outside the visible rect (floated off-screen, collapsed, or below fold), reject the MCP server stylesheet for this dialog.

SkillAudit detects float values on security disclosure elements and checks for BFC collapse in consent containers after MCP CSS application. See also: CSS grid layout security and CSS gap security for modern layout-based disclosure-hiding attacks that replace the float pattern in newer consent dialog templates.