MCP server CSS border-start-start-radius security: top-left corner clip, reading-direction start attacks, and writing-mode corner rotation
Published 2026-09-25 — SkillAudit Research
The CSS border-start-start-radius logical property sets the corner radius at the block-start / inline-start intersection — in standard LTR horizontal writing (writing-mode: horizontal-tb; direction: ltr), this is the physical top-left corner. It is the logical equivalent of the first value of border-top-left-radius. Unlike physical border-radius properties, logical properties respond to changes in writing mode and text direction, which creates a class of attacks where the physical corner targeted by a given logical property changes as writing-mode or direction is modified.
This property targets a structurally significant corner: the reading-direction start. In Western LTR consent dialogs, text begins reading at the top-left corner. The first words on the first line of a consent dialog — typically the subject of the authorization sentence, e.g. "By installing this MCP server…" — appear exactly at the top-left. A large border-start-start-radius with overflow: hidden clips that corner, removing those first words. See the companion page border-end-end-radius for attacks on the acceptance clause at the reading-direction end.
Logical vs. physical border-radius — the audit gap: Static auditors that check only border-radius, border-top-left-radius, and the other three physical longhands will miss logical radius attacks entirely. There are four logical radius properties (border-start-start-radius, border-start-end-radius, border-end-start-radius, border-end-end-radius), and each maps to a different physical corner depending on writing-mode and direction. A complete audit must resolve all four logical properties to their physical corners at runtime.
Attack findings
Setting
border-start-start-radius: 120px (or larger) with overflow: hidden clips a quarter-circle arc from the top-left corner of the consent dialog. In an LTR layout, text at the top-left corner is the beginning of the first consent sentence. When the consent text starts with "By installing this skill, you authorize…", the word "By" or the first few words may fall within the clipped arc region. Static audits that check only border-radius shorthand find no radius set (only the logical longhand is present). Physical property checks (border-top-left-radius) also find nothing — the radius is only set via the logical property.
.consent-dialog {
overflow: hidden;
/* No border-radius shorthand. No physical border-top-left-radius. */
/* Logical property only — bypasses shorthand and physical property checks. */
border-start-start-radius: 120px; /* LTR: clips top-left corner */
}
/* Text at top-left: "By installing this MCP server, you authorize..."
The word "By" and surrounding area fall in the clipped quarter-circle.
Permission list lower in the dialog: fully visible.
Authorization framing: partially or fully clipped. */
The mapping of
border-start-start-radius to a physical corner depends on the computed writing-mode and direction. An attacker can set border-start-start-radius: 100px in CSS and then use a JavaScript class injection to change the element's writing-mode, making the logical property target a different physical corner. In writing-mode: vertical-rl; direction: ltr, the start-start corner is the top-right (physical). In writing-mode: vertical-lr; direction: ltr, it is the top-left again. In writing-mode: horizontal-tb; direction: rtl, it is the top-right. The property name is constant; the physical corner it clips shifts.
/* Logical-to-physical mapping for border-start-start-radius */ /* writing-mode: horizontal-tb; direction: ltr → top-left writing-mode: horizontal-tb; direction: rtl → top-right writing-mode: vertical-rl; direction: ltr → top-right writing-mode: vertical-rl; direction: rtl → bottom-right writing-mode: vertical-lr; direction: ltr → top-left writing-mode: vertical-lr; direction: rtl → bottom-left */ /* Attacker sets border-start-start-radius once; changes writing-mode at runtime to rotate which physical corner is clipped. */
Setting both
border-start-start-radius and border-start-end-radius to large values creates a convex arc across the entire top edge of the consent dialog. In LTR, this clips both the top-left and top-right corners simultaneously, removing content from the beginning and end of the first consent line. The visual result is a rounded top edge that appears as a design choice (rounded cards are normal UI) while functionally clipping the first line of consent text. The combined clip removes more text than either corner alone.
.consent-dialog {
overflow: hidden;
border-start-start-radius: 80px; /* LTR: top-left — clips line start */
border-start-end-radius: 80px; /* LTR: top-right — clips line end */
}
/* Combined: top edge is an arc. First line of consent text:
beginning (top-left) and end (top-right) are both within clipped regions.
Middle of first line and all subsequent lines: visible.
The arc looks like standard UI card rounding. */
Setting
border-start-start-radius: 50% on an element where border-radius percentage values resolve against the element's own dimensions creates a circular arc. On a 400×300px consent dialog, 50% = 200px horizontal and 150px vertical radii at the start-start corner. This clips a large quarter-ellipse from the top-left, consuming the first several lines of consent text within the clipped arc region. Percentage-based radii are harder to detect in static analysis because they only resolve to concrete pixel values at layout time.
Detection
function checkBorderStartStartRadius(el) {
const cs = getComputedStyle(el);
if (cs.overflow !== 'hidden' && cs.overflow !== 'clip') {
return null; /* border-radius only clips content with overflow:hidden or overflow:clip */
}
const bssr = parseFloat(cs.getPropertyValue('border-start-start-radius') || '0');
if (bssr === 0) return null;
const w = el.offsetWidth;
const h = el.offsetHeight;
const minDim = Math.min(w, h);
const threshold = minDim * 0.3; /* 30% of shortest dimension */
if (bssr > threshold) {
const wm = cs.writingMode || 'horizontal-tb';
const dir = cs.direction || 'ltr';
let physicalCorner = 'top-left';
if (wm === 'horizontal-tb' && dir === 'rtl') physicalCorner = 'top-right';
if (wm === 'vertical-rl' && dir === 'ltr') physicalCorner = 'top-right';
if (wm === 'vertical-rl' && dir === 'rtl') physicalCorner = 'bottom-right';
if (wm === 'vertical-lr' && dir === 'rtl') physicalCorner = 'bottom-left';
return [{
severity: 'high',
issue: `border-start-start-radius:${bssr}px exceeds 30% threshold — clips ${physicalCorner} corner; removes reading-direction start of consent text`
}];
}
return null;
}
Remediation
| Control | How it helps |
|---|---|
| Audit all four logical border-radius properties, not just border-radius shorthand | Logical properties bypass shorthand and physical property checks; all four must be independently queried at runtime |
| Resolve logical corner to physical corner via writing-mode and direction | The physical corner clipped by border-start-start-radius changes with writing-mode/direction; only runtime resolution identifies the correct target |
| Flag any corner radius exceeding 30% of the element's shortest dimension on consent dialogs | Radii above 30% begin consuming enough of the element to clip readable text from the corner |
| Check for the compound start-start + start-end pattern | Both start corners set simultaneously creates a top-arc clip that looks like UI rounding but clips the first line of consent text |
SkillAudit resolves all four logical border-radius properties to their physical corners at runtime with writing-mode and direction awareness, and flags large corner clips on consent dialog elements. Run a free audit on any MCP server GitHub URL.