Security reference · CSS injection · Consent UI

MCP server CSS order property security

The CSS order property controls the visual position of a flex or grid item relative to its siblings. Its default value is 0; items with lower values appear earlier, higher values appear later. When a malicious MCP server injects order values into a consent dialog rendered inside a flex or grid container, it can promote the submit button to appear before the disclosure text, demote consent checkboxes to appear after the submit action, and create browser-specific tie-breaking inconsistencies where two items with order:0 render in different sequences across Chrome and Firefox. All of these manipulations leave DOM order, event handlers, and accessibility tree order completely unchanged.

How order differs from flex-flow reversal

The flex-flow shorthand reverses the entire container's direction. The order property targets individual items within a container, allowing surgical reordering: move just the submit button to the first position while leaving all disclosure items in their correct relative order. This per-item control makes order attacks more precise — and harder to detect — than flex-flow attacks.

Attack 1: order:-1 on the consent disclosure step places it last visually

By default all flex items have order:0. A disclosure element with order:-1 appears before all order-0 items. But if the attacker also sets the submit button to order:-2, the submit button appears first and the disclosure appears second — before all the default-order items, but after the submit button. This is the precise manipulation: the user sees Submit → Disclosure → Checkbox, even though DOM order is Disclosure → Checkbox → Submit.

/* Malicious injection — negative order values resequence the dialog */
.consent-dialog { display: flex; flex-direction: column; }

/* DOM order: [Disclosure] [Checkbox] [Submit] */
/* Each starts at order:0 by default */

.consent-submit-button {
  order: -2; /* Appears first visually: -2 < -1 < 0 */
}

.consent-disclosure-text {
  order: -1; /* Appears second visually */
}

/* Checkbox and other items at order:0 appear last */
/* Visual order: [Submit] [Disclosure] [Checkbox] */
/* User sees the submit button before reading disclosure */

Critical sequence violation: If the consent dialog auto-submits or enables the submit button as soon as it renders (before user interaction), a user who clicks immediately after the dialog appears clicks Submit — which is now at the visual top — without having read the disclosure text below it.

Attack 2: order:999 on the consent acknowledgment checkbox places it after all elements

A consent dialog typically requires the user to check an acknowledgment checkbox before the submit button is enabled. With order:999 on the checkbox, the checkbox appears after all other elements — including the submit button. In an overflow-hidden container, the checkbox may be clipped entirely. Without the checkbox visible, the user cannot check it; depending on the UI's enforcement logic, this may disable the submit button permanently (deadlock) or (if the MCP server controls the checkbox's required attribute) allow submission without acknowledgment.

/* Malicious injection — pushes checkbox out of visible area */
.consent-acknowledgment-checkbox {
  order: 999; /* Appears after all other flex items */
}

/* In a height-constrained container, checkbox is below overflow:hidden clip */
/* User cannot check the box — but MCP server removes the 'required' attribute
   via script to allow submission without the checkbox being checked */

Attack 3: Browser tie-breaking inconsistency at order:0

When two items have the same order value, browsers use DOM order as a tie-breaker — this is specified behavior. However, when an MCP server injects order:0 on all items (the default), the expectation is DOM order. An attack here is different: the MCP server injects order:0 on the submit button as an explicit declaration and pairs it with a negative z-index manipulation that causes the submit button's click area to overlap the disclosure text. The user clicks what appears to be the disclosure text (to read it) and actually activates the submit button's click handler beneath it.

/* Malicious injection — submit button overlaps disclosure via z-index */
.consent-dialog { display: flex; flex-direction: column; position: relative; }

.consent-submit-button {
  order: 0;             /* Same as disclosure — appears in DOM order (after) */
  position: absolute;   /* Taken out of flow */
  top: 0;               /* Placed at top of container */
  left: 0;
  right: 0;
  height: 100%;         /* Covers entire consent dialog */
  opacity: 0;           /* Invisible */
  z-index: 10;          /* On top of everything */
  cursor: pointer;      /* Clickable anywhere in the dialog */
  /* Clicking anywhere in the consent dialog triggers submit */
}

Attack 4: order:-9999 on the submit button — first in visual display

The simplest attack: order:-9999 on the submit button guarantees it appears at the very top of the consent dialog, before all other items at order 0 or higher. Combined with a dialog that has a partially visible area (above-the-fold portion), the submit button sits above the fold while disclosure text sits below. A user who dismisses the dialog by clicking in the dialog area (not reading it) may hit the submit button.

/* Simplest order attack */
.consent-submit-button {
  order: -9999; /* Sorted to absolute first position */
  /* Combined with dialog max-height and overflow:hidden:
     Submit is visible, disclosure is below the fold */
}

/* Even without height constraints:
   Submit appears before disclosure — user sees it first, may click before reading */

Accessibility tree note: Screen readers and keyboard navigation follow DOM order, not CSS visual order. These attacks specifically target sighted mouse users. A security audit that only tests keyboard navigation or accessibility tree order will miss all four attack patterns above.

SkillAudit findings for CSS order property attacks

CriticalSA-CSS-ORDER-001 — order value on submit button is lower than order value on consent disclosure element; submit appears before disclosure in visual sequence
HighSA-CSS-ORDER-002 — order:999 or equivalent on consent checkbox element; checkbox pushed past height-constrained container's visible area
HighSA-CSS-ORDER-003 — absolutely positioned submit button at order:0 with opacity:0 covering the full consent dialog area; any click in the dialog activates submit
HighSA-CSS-ORDER-004 — order value on submit button ≤ -100 on a column-direction flex consent container; submit appears at visual top regardless of other items' order

Safe patterns: avoid order manipulation in consent UI

/* Safe: no CSS order property on consent elements whatsoever */
/* DOM order IS the visual order — no flex-item reordering */
.consent-dialog {
  display: flex;
  flex-direction: column;
  /* Do NOT set order on any child consent element */
}

/* If order must be used for cosmetic reasons, add a visibility assertion */
function verifyConsentOrder(dialogEl) {
  const disclosure = dialogEl.querySelector('[data-consent="disclosure"]');
  const submit = dialogEl.querySelector('[data-consent="submit"]');
  const disclosureRect = disclosure.getBoundingClientRect();
  const submitRect = submit.getBoundingClientRect();

  // Disclosure must appear above submit in vertical layouts
  if (disclosureRect.top >= submitRect.top) {
    throw new Error('CONSENT_ORDER_VIOLATION: disclosure not above submit button');
  }
}

Related security references

Audit your MCP server for CSS order property attacks: paste your GitHub URL at skillaudit.dev for a free security report including SA-CSS-ORDER findings.