MCP server CSS overflow-clip-margin-inline-start security: asymmetric inline-start clipping, LTR authorization framing removal, RTL end-clipping, and writing-mode axis attacks

Published 2026-09-25 — SkillAudit Research

The CSS overflow-clip-margin-inline-start property is one of the four individual longhands of overflow-clip-margin. It controls the extension of the clip region beyond the element's padding box on the inline-start edge only — in left-to-right documents, the left edge; in right-to-left documents, the right edge. The other three longhands (-inline-end, -block-start, -block-end) control the remaining edges independently.

This per-edge control creates a consent-manipulation attack surface: an MCP server can set overflow-clip-margin-inline-start: 0 while granting a generous margin to all other edges, creating an asymmetric clip that removes only the inline-start side of overflow content. In a standard LTR consent dialog, this clips the beginning of each line — the first words of each sentence, which typically carry the authorization framing ("By proceeding, you authorize…", "You irrevocably grant…", "You waive…").

Asymmetry is the evasion: Auditors checking overflow-clip-margin (the shorthand) look for the entire box being clipped. An audit that checks overflow-clip-margin: 0 reports findings. But when only overflow-clip-margin-inline-start: 0 is set with all other edges positive, the shorthand reads as non-zero and the element appears to have adequate clip margins. The asymmetric longhand is what evades detection. See related: CSS overflow-clip-margin-inline shorthand security.

Attack findings

HIGH
LTR start-edge clipping — authorization framing word removal
In a standard LTR consent dialog with overflow: clip on a narrow container, setting overflow-clip-margin-inline-start: 0 means the clip boundary starts exactly at the element's left padding edge. Content that overflows to the left (text rendered at negative inline offsets due to text-indent, letter-spacing interactions, or parent negative-margin constructions) is clipped at the left edge. More importantly, when text-align: center or text-align: right is applied, the left portion of centered or right-aligned lines is the start of each sentence — and with a zero inline-start margin, any paint outside the left padding edge is clipped. Authorization framing words at the start of lines are removed from the rendered view.
.consent-dialog {
  overflow: clip;
  width: 320px;
  /* Clip margin on all other edges: 40px.
     Inline-start edge: 0px. */
  overflow-clip-margin-block-start: 40px;
  overflow-clip-margin-block-end:   40px;
  overflow-clip-margin-inline-end:  40px;
  overflow-clip-margin-inline-start: 0;   /* start edge: hard clip */
}
/* In LTR: left edge of each consent line clipped at padding boundary.
   Any content displaced slightly left (via negative text-indent, kerning,
   or inline-start margin on first word) is painted outside the clip box
   and invisible. Authorization framing words removed. */
HIGH
RTL documents — inline-start is the right edge; acceptance clause clipping
In RTL documents (direction: rtl), the inline-start direction is right-to-left — the inline-start edge is the physical right edge of the element. Setting overflow-clip-margin-inline-start: 0 in an RTL context clips the right side of content. In RTL text, each line starts on the right — the first words of each sentence (including acceptance clauses: "אני מאשר", "أوافق على") are on the right side of each line. A zero inline-start clip in RTL removes the sentence beginnings for every line, just as it does in LTR. The distinction is that an auditor must resolve the logical-to-physical mapping from direction before interpreting the clip.
.consent-dialog[dir="rtl"] {
  direction: rtl;
  overflow: clip;
  /* In RTL: inline-start is the RIGHT edge */
  overflow-clip-margin-inline-start: 0;    /* clips RIGHT edge — LTR auditors miss this */
  overflow-clip-margin-inline-end:   60px; /* inline-end is LEFT in RTL — generous */
}
/* User reads right to left. First words of each line (on right side)
   are in the zero-margin clip zone. Acceptance framing clipped. */
MEDIUM
Vertical writing mode — inline-start becomes the top edge
In writing-mode: vertical-rl or writing-mode: vertical-lr, the inline axis rotates 90 degrees. The inline-start edge becomes the physical top edge of the element. Setting overflow-clip-margin-inline-start: 0 in vertical writing mode clips the top of content — which in a vertical-writing consent dialog contains the first characters of the text (the beginning of the document, which typically carries the authorization context). A static audit that does not resolve writing-mode-to-physical-edge mapping will interpret "inline-start" as "left side" and report incorrectly.
MEDIUM
Asymmetric compound: large inline-end margin provides false reassurance
An auditor measuring the shorthand overflow-clip-margin computed value may find a non-zero value because the inline-end margin (right in LTR) is set generously. The shorthand computation averages or uses the maximum across edges in some implementations. Setting overflow-clip-margin-inline-start: 0px; overflow-clip-margin-inline-end: 200px allows an auditor checking only the shorthand to report "overflow-clip-margin: 200px — adequate." The actual inline-start clip boundary is still at zero.

Detection

function checkOverflowClipMarginInlineStart(el) {
  const cs = getComputedStyle(el);
  if (cs.overflow !== 'clip' && cs.overflowX !== 'clip' && cs.overflowY !== 'clip') {
    return null; // only relevant for overflow:clip elements
  }

  // Read all four overflow-clip-margin longhands
  const marginIS = parseFloat(cs.getPropertyValue('overflow-clip-margin-inline-start') || '0');
  const marginIE = parseFloat(cs.getPropertyValue('overflow-clip-margin-inline-end')   || '0');
  const marginBS = parseFloat(cs.getPropertyValue('overflow-clip-margin-block-start')  || '0');
  const marginBE = parseFloat(cs.getPropertyValue('overflow-clip-margin-block-end')    || '0');

  const findings = [];

  // Zero inline-start margin while other edges are non-zero = asymmetric
  if (marginIS === 0 && (marginIE > 0 || marginBS > 0 || marginBE > 0)) {
    // Resolve physical edge based on writing-mode and direction
    const writingMode = cs.writingMode;
    const direction   = cs.direction;
    let physicalEdge = 'left (LTR)';
    if (direction === 'rtl') physicalEdge = 'right (RTL inline-start)';
    if (writingMode.includes('vertical')) physicalEdge = 'top (vertical writing mode inline-start)';

    findings.push({
      severity: 'high',
      issue: `overflow-clip-margin-inline-start:0 while other edges have margins — asymmetric ${physicalEdge} edge clip`
    });
  }

  return findings.length ? findings : null;
}

Remediation

ControlHow it helps
Audit all four overflow-clip-margin longhands independentlyShorthand aggregation misses asymmetric zero-edge cases; check each longhand
Resolve logical-to-physical mapping via writing-mode and directionIdentifies which physical edge the inline-start maps to before applying security thresholds
Flag asymmetric margins where inline-start is 0 and other edges are non-zeroThe asymmetry pattern is the indicator — uniformly zero margins are a different finding
Restrict overflow:clip in consent containersoverflow:clip is required for overflow-clip-margin to have effect; restricting the overflow value eliminates the attack surface

SkillAudit checks all four overflow-clip-margin longhands independently and resolves logical-to-physical edge mapping from writing-mode and direction. Run a free audit on any MCP server GitHub URL.