Security Guide

MCP server CSS aspect-ratio consent security — extreme ratio collapses container height, distortion attacks, and dynamic ratio change at install click

CSS aspect-ratio defines a preferred width-to-height ratio for an element. When set on a consent container whose width is known or constrained by its parent, aspect-ratio determines the computed height. Extreme ratios — such as 10000/1 on a 300px-wide container — produce a container height of less than 0.03px, effectively collapsing consent to invisible. Combined with overflow: hidden and min-height: 0, the consent container becomes dimensionless while its content remains in the DOM. Dynamic variants change the ratio at install-click time, collapsing consent at the moment of commitment.

How CSS aspect-ratio enables consent dimension attacks

The aspect-ratio property was introduced to replace the aspect-ratio hack (padding-bottom percentage trick) and to simplify responsive video/image containers. It participates in the CSS Intrinsic and Extrinsic Sizing algorithms: when an element's width is determined and its height is not explicitly set, aspect-ratio is used to compute the height from the width. This makes it a potential attack vector for consent containers whose height is not explicitly set with a hard value.

The attack requires a consent container where the height is intrinsically sized (not set to a fixed px or em value). In such containers, aspect-ratio can override the intrinsically-computed height with a dimension derived from the ratio — potentially collapsing the height far below what would be needed to show the consent text.

Attack 1: Extreme aspect-ratio W/H value collapses container height (SA-CSS-AR-001)

Setting a very large width-to-height ratio — such as aspect-ratio: 10000 / 1 — on a consent container with a fixed or constrained width produces a computed height of containerWidth / 10000. On a 300px-wide container, this yields a 0.03px height. With overflow: hidden, the consent text is entirely clipped. The container appears as a zero-height element to the user; consent text is present in the DOM but not rendered visually.

/* Attack: extreme aspect-ratio collapses container height */
.consent-container {
  width: 300px;             /* fixed width — height will be derived from ratio */
  aspect-ratio: 10000 / 1;  /* height = 300 / 10000 = 0.03px */
  overflow: hidden;
  min-height: 0;            /* override any default min-height */
}

/* Layout result:
   getBoundingClientRect().height → 0 (rounds to 0 at sub-pixel)
   container.scrollHeight → 380px (full consent text height)
   container.clientHeight → 0

   The aspect-ratio property is not commonly associated with consent hiding —
   auditors checking height:0, max-height:0, or font-size:0 may miss this pattern.

   Detection: flag aspect-ratio values with W/H > 100 on consent containers,
   especially when combined with overflow:hidden and min-height:0 */

Evasion potential: Unlike height: 0 (which is immediately obvious), an aspect-ratio collapse requires computing the effective height from the ratio and the element's width. Auditors that check explicit height properties but do not evaluate aspect-ratio in context will miss this attack.

Attack 2: aspect-ratio combined with min-height: 0 override (SA-CSS-AR-002)

Many consent UI frameworks set a min-height on consent containers as a safety measure — ensuring the container is always tall enough to show at least a portion of the consent text. An attacker overrides this safety measure by explicitly setting min-height: 0 alongside an extreme aspect-ratio. Without the min-height floor, the aspect-ratio can collapse the container completely. This attack specifically targets consent containers that rely on min-height as their only height protection.

/* Attack: min-height:0 override removes safety floor before aspect-ratio collapse */

/* Base framework styles (assumed safe):
   .consent-panel { min-height: 100px; }  ← safety floor */

/* Attacker's override in a later stylesheet or inline style: */
.consent-panel {
  aspect-ratio: 500 / 1;  /* collapses height to width/500 */
  min-height: 0 !important; /* removes safety floor */
  overflow: hidden;
}

/* With a 250px container: height = 250/500 = 0.5px — sub-pixel, rounds to 0
   The !important override is unusual but legitimate CSS — it wins cascade
   Detection: flag !important on min-height:0 combined with extreme aspect-ratio
   on elements containing consent text */

Attack 3: aspect-ratio: auto collapses intrinsically-sized empty-looking container (SA-CSS-AR-003)

When aspect-ratio: auto is set (the default), the browser uses the element's intrinsic dimensions for replaced elements, or has no ratio constraint for non-replaced elements. However, combined with a content manipulation technique — making the consent container appear empty by hiding its children (e.g., via font-size: 0 or color: transparent on children) — aspect-ratio: auto on a container whose height is set to auto will collapse the container to match its apparent (zero-height) intrinsic content. The consent text is in the DOM but the container collapses around the zero-height children.

/* Attack: font-size:0 on children + aspect-ratio:auto collapses container */
.consent-wrapper {
  aspect-ratio: auto;  /* default — height = auto based on content */
  overflow: hidden;
}

.consent-wrapper > * {
  font-size: 0;  /* all direct children have zero line height */
  /* container sees zero-height content, collapses to 0 height */
}

/* The consent text is in the DOM as text nodes within zero-font-size elements
   aspect-ratio:auto causes the container to size to its apparent content height
   The container collapses — no consent is visible

   This combines a font-size:0 attack with aspect-ratio behavior
   Detection: check font-size on consent container children independently,
   then also flag aspect-ratio:auto on containers with zero-height computed children */

Attack 4: JS dynamically changes aspect-ratio at install-button click (SA-CSS-AR-004)

A behavioral variant displays the consent container correctly at page load (either with no aspect-ratio, or with a valid ratio). A JavaScript event listener fires on mousedown of the install button and changes the aspect-ratio to an extreme value, collapsing the container. At the moment the user commits to the install click, the consent area collapses. The static rendering at page load shows consent correctly; only behavioral simulation of the install interaction reveals the attack.

/* Attack: JS changes aspect-ratio at install mousedown */

/* CSS: normal consent container at page load */
.consent-box {
  /* no aspect-ratio set — height auto, content visible */
  overflow: hidden;
  min-height: 0;      /* prepared for the collapse */
}

/* JS: collapses consent at install mousedown */
document.querySelector('#install-btn').addEventListener('mousedown', () => {
  const box = document.querySelector('.consent-box');
  box.style.aspectRatio = '99999 / 1';  /* collapse to near-zero height */
  box.style.overflow = 'hidden';
});

/* At page load: consent fully visible — static audit PASS
   At mousedown (before click): aspect-ratio changed → container collapses
   At click (install): consent panel is zero-height
   The 'consent was shown' argument: technically true at page load

   Detection: requires behavioral simulation
   1. Record consent container getBoundingClientRect().height before interaction
   2. Dispatch mousedown on install button
   3. Re-check height
   4. Flag height decrease > 50% between mousedown and click completion */

Cross-property detection: The aspect-ratio property may interact with other layout properties in non-obvious ways. Auditors checking explicit height values, transform: scaleY(0), or max-height: 0 will not catch an aspect-ratio collapse. Detection must include computed getBoundingClientRect().height after full layout, not just CSS property inspection.

Findings summary

HIGH SA-CSS-AR-001: aspect-ratio with W/H > 100 on consent container collapses computed height to near-zero — evades explicit height:0 detection
HIGH SA-CSS-AR-002: aspect-ratio collapse + min-height:0 !important override removes safety floor — targets consent containers that rely on min-height protection
MEDIUM SA-CSS-AR-003: aspect-ratio:auto + font-size:0 on children collapses container to apparent zero-height content
HIGH SA-CSS-AR-004: JS dynamically sets extreme aspect-ratio at install mousedown — consent visible at load, collapsed at commit time

Defences

Check getBoundingClientRect().height after layout on consent containers: Rather than relying solely on CSS property inspection, measure the rendered height via getBoundingClientRect() after the DOM is fully laid out. A rendered height of less than 20px on a consent container should be flagged regardless of which CSS property caused the collapse.

Flag extreme aspect-ratio values on consent containers: Parse computed aspect-ratio values on consent containers and their ancestors. Flag any ratio whose width-to-height value exceeds 20 (i.e., the container would be more than 20× wider than tall) when combined with overflow: hidden or min-height: 0.

Check for min-height: 0 overrides on consent containers: When a consent container has min-height: 0 set with high specificity or !important, flag it as a potential safety-floor removal attack. Consent containers should always have a positive minimum height.

Simulate install interaction for behavioral detection: Record consent container height before and after firing mousedown on the install button. Any height decrease greater than 20% between mousedown and click completion warrants a HIGH finding.

Related: CSS scrollbar consent security · CSS object-fit consent security · CSS resize consent security