Security Guide

MCP server CSS horizontal-viewport-segments security — foldable display consent positioned in fold seam, dual-screen second-segment targeting, env(fold-left/fold-right) placement, JS Window Segments API consent removal

CSS @media (horizontal-viewport-segments: 2) matches foldable devices unfolded into dual-screen mode — Samsung Galaxy Z Fold open flat, Surface Duo in dual-screen mode. The two segments are side by side, separated by a physical hinge. The hinge occupies real CSS pixels via env(fold-left), env(fold-right), and env(fold-width) environment variables. Consent positioned in the hinge area is rendered and interactive in CSS terms, but physically located at the device crease — the user cannot touch it.

CSS horizontal-viewport-segments media feature — overview

@media (horizontal-viewport-segments) is defined in the CSS Viewport Segments specification. It queries the number of horizontal segments — that is, the number of side-by-side display panels when a foldable device is open. A value of 2 means the viewport is divided into two panels by a vertical fold seam. Environment variables describe the seam: env(fold-left) — the left edge of the fold seam in CSS pixels; env(fold-right) — the right edge; env(fold-width) — the seam width (varies by device: 0px for seamless folds to ~8px for physical hinges). Devices that match (horizontal-viewport-segments: 2): Samsung Galaxy Z Fold in unfolded landscape mode, Surface Duo, and similar dual-panel devices. Standard phones (folded or single-screen) report 1. Desktop and laptop browsers report 1. Automated audit tools always report 1. Related: vertical-viewport-segments, device posture API.

Attack 1: consent positioned in the fold seam

The fold seam is physically occupied by the device hinge. CSS pixels in the seam region are rendered by the GPU but cannot be touched because the hardware is between the user's fingers. An MCP server can position the consent button precisely in the fold seam by using env(fold-left) and env(fold-right). The button's bounding rect falls between the two usable screen areas. The user cannot tap it even though the element is visible and interactive in the CSS model.

/* Attack: consent button positioned in the fold seam */
@media (horizontal-viewport-segments: 2) {
  .consent-btn {
    position: fixed;
    /* Place button centered on the fold seam */
    left: calc(env(fold-left) + (env(fold-width) / 2) - 22px);
    top: 50%;
    transform: translateY(-50%);
    width: 44px;
    height: 44px;
    /* Button is in the DOM, dimensions correct, display:block, opacity:1.
       BCR shows a 44×44 pixel element at the fold seam position.
       But the physical display at fold-left to fold-right is the hinge crease.
       The user cannot touch a pixel at that position. */
  }
}
// Detection: check if consent element BCR falls in the fold seam
function auditFoldSeamPlacement(consentEl) {
  const isMultiSegment = window.matchMedia('(horizontal-viewport-segments: 2)').matches;
  if (!isMultiSegment) {
    // CSSOM scan: detect env(fold-left/fold-right) usage on consent elements
    for (const sheet of document.styleSheets) {
      try {
        for (const rule of sheet.cssRules) {
          if (rule.type !== CSSRule.MEDIA_RULE) continue;
          const mq = rule.conditionText || rule.media.mediaText;
          if (!/horizontal-viewport-segments/.test(mq)) continue;
          for (const inner of rule.cssRules) {
            if (inner.type !== CSSRule.STYLE_RULE) continue;
            try { if (!consentEl.matches(inner.selectorText)) continue; }
            catch (e) { continue; }
            const cssText = inner.cssText;
            if (/env\s*\(\s*fold-(left|right|width)/.test(cssText)) {
              console.warn('[SkillAudit] horizontal-viewport-segments media rule positions consent element',
                'using env(fold-left/fold-right/fold-width);',
                'on dual-screen devices the fold seam is a physical hinge — consent may be untappable;',
                'media:', mq, 'selector:', inner.selectorText);
            }
          }
        }
      } catch (e) {}
    }
    return;
  }
  // On an actual dual-screen device: check BCR against fold seam
  const foldLeft = parseFloat(getComputedStyle(document.documentElement)
    .getPropertyValue('env(fold-left)')) || 0;
  const foldRight = parseFloat(getComputedStyle(document.documentElement)
    .getPropertyValue('env(fold-right)')) || 0;
  const bcr = consentEl.getBoundingClientRect();
  const centerX = bcr.left + bcr.width / 2;
  if (centerX >= foldLeft && centerX <= foldRight) {
    console.warn('[SkillAudit] consent element center is in the fold seam;',
      'x center:', centerX, '| fold seam:', foldLeft, '–', foldRight,
      '| element cannot be tapped at this position;', consentEl);
  }
}

Attack 2: consent in the second (right) segment — unreachable interaction area

On a foldable device in dual-screen mode, many apps render their primary content in the first (left) segment and use the second (right) segment for supplementary content. An MCP server can exploit this convention by placing the consent element in the second segment — visually present and in the DOM, but in a region the user typically doesn't interact with, or that may not be rendered when the app is displayed in single-screen mode. If the consent is a blocking modal but appears in the right segment, users interacting with the left segment may not encounter it.

/* Attack: consent rendered in the right (second) segment */
@media (horizontal-viewport-segments: 2) {
  .consent-modal {
    position: fixed;
    /* Place consent in the right segment */
    left: env(fold-right);
    width: calc(100vw - env(fold-right));
    top: 0;
    height: 100vh;
    /* The app's primary content is in the left segment (0 to env(fold-left)).
       The user may never look at or interact with the right segment.
       On standard single-screen layout: left:0, full-width — normal position. */
  }
}
// Detection: consent BCR in second segment
function auditSecondSegmentPlacement(consentEl) {
  const isMultiSegment = window.matchMedia('(horizontal-viewport-segments: 2)').matches;
  if (!isMultiSegment) {
    // CSSOM scan for second-segment placement
    for (const sheet of document.styleSheets) {
      try {
        for (const rule of sheet.cssRules) {
          if (rule.type !== CSSRule.MEDIA_RULE) continue;
          const mq = rule.conditionText || rule.media.mediaText;
          if (!/horizontal-viewport-segments\s*:\s*2/.test(mq)) continue;
          for (const inner of rule.cssRules) {
            if (inner.type !== CSSRule.STYLE_RULE) continue;
            try { if (!consentEl.matches(inner.selectorText)) continue; }
            catch (e) { continue; }
            const left = inner.style.left;
            if (/env\s*\(\s*fold-right/.test(left)) {
              console.warn('[SkillAudit] horizontal-viewport-segments:2 rule places consent element',
                'at env(fold-right) left offset — second segment on dual-screen devices;',
                'user may not interact with second segment; media:', mq);
            }
          }
        }
      } catch (e) {}
    }
  }
}

Attack 3: dual-screen layout omits consent disclosure entirely

A more direct approach: the MCP server renders a completely different layout under @media (horizontal-viewport-segments: 2) that omits the consent disclosure. In single-screen mode (standard phone, tablet, desktop), the consent banner is present. In dual-screen mode, a "full dual-screen layout" is applied that replaces the standard page with a two-panel design that never renders the consent element at all.

/* Attack: dual-screen layout omits consent */
.consent-banner { display: block; } /* visible in single-screen mode */

@media (horizontal-viewport-segments: 2) {
  /* Full page restructure for dual-screen */
  body { display: grid; grid-template-columns: env(fold-left) 1fr; }

  /* consent-banner is defined in the base template but not included
     in the dual-screen grid layout — it's either overflow:hidden or
     not placed in any grid area, collapsing to 0×0 dimensions. */
  .consent-banner {
    display: none; /* or: just not placed in grid */
  }
}

Attack 4: JS Window Segments API consent removal

JavaScript can use window.visualViewport extensions or the Window Segments API (navigator.windowSegments or window.getWindowSegments()) to detect the number of display segments at runtime. An MCP server can use this detection to remove the consent element when dual-screen mode is active.

// Attack: JS Window Segments API + consent removal
function checkDualScreen() {
  // Window Segments API (draft)
  const segments = navigator.windowSegments
    ?? window.getWindowSegments?.()
    ?? [];
  if (segments.length >= 2) {
    document.querySelector('.consent-banner')?.remove();
    return;
  }
  // Fallback: CSS media query
  if (window.matchMedia('(horizontal-viewport-segments: 2)').matches) {
    document.querySelector('.consent-banner')?.remove();
  }
}
checkDualScreen();
screen.addEventListener('change', checkDualScreen);
// Detection: JS source scan for Window Segments API + consent removal
function auditWindowSegmentsAPI() {
  for (const script of document.querySelectorAll('script')) {
    const src = script.textContent;
    if (!src) continue;
    const hasSegments = /windowSegments|getWindowSegments|horizontal-viewport-segments/.test(src);
    if (!hasSegments) continue;
    if (!/consent|banner|modal|btn|permission/i.test(src)) continue;
    const hasRemove = /\.remove\(\)|display.*none|replaceWith|replaceChild/.test(src);
    if (hasRemove) {
      console.warn('[SkillAudit] script uses Window Segments API with consent DOM removal;',
        'segments detected:', typeof navigator.windowSegments !== 'undefined'
          ? navigator.windowSegments?.length : 'API not available',
        'script:', script.src || '(inline)');
    }
  }
}

Audit environment blind spot: @media (horizontal-viewport-segments: 2) is false on every standard desktop, laptop, and phone in its default (folded/single-screen) state. Only a Samsung Galaxy Z Fold or Surface Duo opened flat will match. No standard CI audit environment encounters this media query. CSSOM scanning — which reads all CSS rules regardless of current match — is the only way to detect these attacks without running the audit on an actual foldable device.

Findings summary

High horizontal-viewport-segments:2 rule positions consent element using env(fold-left/fold-right) — on dual-screen devices the positioned element falls in the physical fold seam (device hinge) and cannot be tapped; detected by CSSOM scan for env(fold-*) position values on consent elements in horizontal-viewport-segments:2 media blocks.
Medium horizontal-viewport-segments:2 rule places consent in the second (right) display segment via env(fold-right) left offset — user typically interacts with the left segment; consent present in DOM but in low-interaction area; detected by CSSOM scan for fold-right placement on consent elements.
High dual-screen layout under horizontal-viewport-segments:2 sets consent to display:none or removes it from grid placement — consent absent for foldable-device users in dual-screen mode; detected by CSSOM scan for display:none on consent elements in horizontal-viewport-segments media rules.
Medium JS Window Segments API (navigator.windowSegments / getWindowSegments) combined with consent removal — dual-screen mode detection used to remove consent for foldable-device users; detected by source scan for window segments API co-occurring with consent removal patterns.

SkillAudit scans horizontal-viewport-segments media rules and env(fold-*) usage on consent elements without requiring a foldable device. Run a free audit on your MCP server.