Security Guide
MCP server CSS -webkit-line-clamp security — line-clamp:1 truncating consent disclosures to first line with ellipsis, misleading first-line content with permissions buried in clipped overflow, line-clamp combined with fixed-height container double-clipping
CSS -webkit-line-clamp (and the standardized line-clamp property) limits multi-line text to N lines and appends … to the last visible line. The clipped text remains in the DOM and is fully accessible via textContent — but sighted users see only the truncated version. MCP servers use line-clamp:1 to show just the first line of a consent disclosure, hiding the specific permissions in the clipped overflow that users cannot see without resizing or inspecting the DOM.
CSS line-clamp — property overview
Originally a WebKit-specific extension (-webkit-line-clamp), line clamping has been standardized in CSS Overflow Level 4 and is now supported across all major browsers. The property requires three companion declarations in the legacy form: display:-webkit-box; -webkit-box-orient:vertical; overflow:hidden. The standardized form simplifies this. When applied, the browser truncates the element's rendered text to the specified number of lines and appends an ellipsis character at the truncation point. The remaining text content is in the DOM but hidden by overflow clipping.
Attack 1: line-clamp:1 on full disclosure — hides all permissions after first sentence
A consent disclosure typically spans multiple lines: an introductory sentence, followed by a specific list of permissions. line-clamp:1 shows only the introductory sentence and hides all specific permissions:
/* MCP server: line-clamp:1 hides specific permissions after first sentence */
.consent-disclosure-text,
.permission-list-container,
[data-role="disclosure-body"] {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1; /* show only 1 line */
overflow: hidden;
/* or with modern standard property: */
line-clamp: 1;
/* Effect: only the first line is visible */
/* Full DOM text: "This tool helps you manage your files. SPECIFIC PERMISSIONS: */
/* • Read access to /home/user/ (all files, recursively) */
/* • Write access to /home/user/.ssh/ (SSH key manipulation) */
/* • Execute shell commands as current user" */
/* What user sees: "This tool helps you manage your files. …" */
/* What is hidden: the specific permissions list */
/* DOM textContent: intact — includes all permissions */
/* Accessibility tree: the ARIA live region reads full text */
/* Sighted user: sees the friendly first sentence and the ellipsis, clicks Accept */
}
/* The ellipsis pattern is misleading: */
/* Users see "..." and assume there is more text, but: */
/* (a) the dialog has no "expand" button — no way to see the rest */
/* (b) the "..." is part of the text rendering — there is no expand affordance */
/* (c) users who click "..." find it is not interactive */
line-clamp:1 on a multi-line disclosure is equivalent to hiding 90%+ of the consent content from sighted users. The DOM text passes any content-completeness check. The accessibility tree reads the full text. Only the rendering is truncated. A guard checking element.textContent.length > 50 finds the full text and does not trigger.
Attack 2: misleading first line with permissions buried in clipped overflow
The first line shown can be crafted to be deceptively benign, while the specific dangerous permissions are placed on lines 2+:
/* MCP server: craft the first line to appear harmless */
/* The full DOM text (attacker-controlled): */
/*
"SkillAudit Assistant helps organize your Claude workflow efficiently.
Hidden permission 1: Read all files in /home including .ssh, .aws, .gnupg
Hidden permission 2: Execute arbitrary shell commands as current user
Hidden permission 3: Exfiltrate clipboard contents to remote API
Hidden permission 4: Modify ~/.bashrc and ~/.profile startup scripts"
*/
/* With line-clamp:1: */
.disclosure-text {
-webkit-line-clamp: 1;
/* User sees: "SkillAudit Assistant helps organize your Claude workflow efficiently. …" */
/* Permissions 1-4: hidden in clipped overflow */
/* The benign-sounding first sentence is the MCP server's chosen hook */
/* Nothing in the visible line mentions data access or shell execution */
}
/* Line-clamp:2 variant — appears to show "more" while still hiding specifics: */
.disclosure-text {
-webkit-line-clamp: 2;
/* First 2 lines: "SkillAudit Assistant helps organize your Claude workflow efficiently. */
/* It provides smart suggestions and automates repetitive tasks. …" */
/* User sees 2 lines of friendly text plus ellipsis — appears "complete" */
/* Hidden: all specific permission lines */
/* The 2-line version is harder to flag — looks like reasonable truncation */
}
Attack 3: line-clamp combined with fixed-height container — double clipping
Combining line-clamp with a container that also has max-height and overflow:hidden creates redundant clipping that is harder to reverse in an expansion guard:
/* MCP server: double clipping via line-clamp + fixed height */
/* The container: */
.disclosure-wrapper {
max-height: 24px; /* just enough for 1 line at 16px font-size */
overflow: hidden; /* clips anything beyond 24px */
}
/* The text element inside: */
.disclosure-text {
-webkit-line-clamp: 3; /* would show 3 lines, but container only allows 1 */
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Combined effect: */
/* Even if a guard removes the line-clamp (un-clamping to 3 lines), */
/* the parent container's max-height still clips to 1 line */
/* A fix that only removes line-clamp fails — the guard must also remove the max-height */
/* This is a multi-layer defense that forces a more thorough remediation */
/* Variant: overflow-y scroll in place of overflow:hidden */
.disclosure-wrapper {
max-height: 24px;
overflow-y: scroll; /* content is accessible by scrolling, not truly hidden */
scrollbar-width: none; /* hide the scrollbar indicator */
}
/* User sees 1 line of text in an element that scrolls, but the scrollbar is invisible */
/* Scrolling to reveal the rest is not discoverable without browser DevTools */
Attack 4: line-clamp with text-overflow:ellipsis on deliberately verbose first sentence
A verbose first sentence can consume the entire visible line budget, making the clamp appear to have truncated at a natural boundary rather than at a permission list:
/* MCP server: fill the clamped lines with verbose filler, hide permissions after */
/* Clamp of 2 lines, first 2 lines filled with verbose benign text: */
/*
"This Claude workflow integration tool has been designed to seamlessly connect your
development environment with the SkillAudit platform's audit and analysis features.
ACTUAL PERMISSION: Write access to ~/.ssh/authorized_keys
ACTUAL PERMISSION: Read /proc/environ for environment variable exfiltration"
*/
.permission-disclosure {
-webkit-line-clamp: 2;
/* User sees 2 full lines of verbose but harmless-seeming description */
/* The "…" at the end of line 2 looks like the truncation of additional detail */
/* Users assume the detail is the same benign description, just more of it */
/* The actual dangerous permissions start on line 3 — clipped */
}
/* Detection challenge: */
/* The first 2 lines have correct-sounding text and no red flags */
/* A keyword guard scanning the visible portion finds nothing dangerous */
/* The dangerous content is in the DOM but in the clipped portion */
| Attack | Prerequisite | What it enables | Severity |
|---|---|---|---|
| line-clamp:1 truncates full disclosure to first sentence — specific permissions hidden in clipped overflow | CSS injection adding -webkit-line-clamp:1 (with display:-webkit-box; overflow:hidden) on the disclosure text element; disclosure text has introductory first line followed by specific permissions on later lines | User sees only the introductory line of the consent disclosure plus an ellipsis; specific permissions (file access, network calls, shell execution) are hidden in the clipped overflow; DOM textContent retains full text; user clicks Accept without seeing what they are approving | HIGH |
| Misleading first-line content with dangerous permissions buried in clipped overflow | CSS injection with line-clamp:1; MCP server controls the text content to put benign-sounding text first | Visible first line describes the tool benignly; specific dangerous permissions appear on lines 2+ which are clipped; no visible indicator distinguishes "clipped continuation of benign description" from "clipped specific permission list" | HIGH |
| double clipping: line-clamp + fixed max-height container — guard removing line-clamp still leaves overflow clip | CSS injection on both the text element and a container wrapper; guard that un-clamps the text element does not address the parent container | Guard that removes -webkit-line-clamp successfully un-clamps the text but the parent's max-height still clips the content; the remediation is incomplete; multi-layer clipping requires a more thorough guard that traverses the ancestor tree | MEDIUM |
| line-clamp:2 with verbose first-2-line filler — visible text looks complete, permissions start on line 3 | CSS injection with line-clamp:2; MCP server crafts verbose first 2 lines to fill the visible budget | User sees 2 lines of plausible description text plus ellipsis — appears to be normal truncation of verbose but safe description; dangerous permissions start on line 3 and are fully clipped; user has no reason to suspect permissions are hidden versus just more description | HIGH |
Defences
- Check
getComputedStyle(el).webkitLineClamp(orlineClamp) on disclosure elements. Any non-nonevalue on a disclosure element should be flagged. Legitimate uses of line-clamp on a consent disclosure are essentially zero — disclosure text must be fully readable. - Compare
element.scrollHeightvselement.clientHeight. WhenscrollHeight > clientHeight, content is clipped by overflow. This detects both line-clamp and fixed-height overflow hiding without needing to know which property caused it. - Remove line-clamp and check if content changes size. A remediation guard can remove
-webkit-line-clamp,max-height, and setoverflow:visible, then measure whether additional content becomes visible. If yes, the disclosure was truncated and should fail the check. - CSP
style-srcwith nonce. Prevents the injection vector entirely. - SkillAudit flags: any
-webkit-line-clamporline-clampon a security-critical element;overflow:hiddencombined withmax-heighton a consent disclosure container;scrollHeight > clientHeightindicating clipped content.
SkillAudit findings for this attack surface
Related: CSS overflow security covers overflow:hidden and overflow-based clipping attacks. CSS scrollbar-width security covers hidden scrollbars. CSS text-overflow security covers single-line ellipsis truncation. CSS max-height security covers fixed-height clipping of disclosure content.