v149 · Browser Intervention · Security · Clickjacking

Attack Scenario

A malicious parent page applies SVG filters to a cross-origin iframe to disguise a payment button as something innocent. Chrome 149 blocks this: filters no longer render across the cross-origin boundary. This page shows the attack mechanism and Chrome 149's defence.

How the attack works

1
Attacker embeds a cross-origin iframe containing a trusted payment/consent button (e.g. "Pay Now" from a payment provider, or "Allow" from an OAuth flow).
2
The parent page wraps the iframe in an SVG <filter> that distorts colour, inverts, or blurs — making the trusted button look like something benign ("Continue Reading", "Close Ad").
3
User clicks what they think is the innocent button. The click lands on the trusted iframe's real button. Payment is authorised, or permission is granted, without user understanding.
4
Chrome 149 fix: SVG filters are not rendered across the cross-origin iframe boundary. The compositor traverses the effect tree and removes filters when crossing origin. The trusted content looks exactly as intended.
Pre-Chrome 149 — Filter applies to cross-origin iframe

Apply a filter to the "trusted button" below:

✓ Confirm Payment — $48.48
↑ This would be a cross-origin iframe in a real attack
Filter active — button disguised. User clicks, not knowing what they're confirming.
Chrome 149+ — Filter blocked at cross-origin boundary

Same filter applied — but compositor blocks it across origin:

✓ Confirm Payment — $48.48
↑ Filter stripped at cross-origin boundary by Chrome 149
Filter blocked — button renders exactly as the payment provider intended. User sees the real UI.

the security boundary

/* Malicious parent page */
.wrapper {
  filter: url('#disguise-filter'); /* tries to apply to iframe */
}

/* Chrome 149 compositor behavior:
   While traversing the render layer for .wrapper's filter effect:
   - Checks: does this cross a cross-origin boundary?
   - If yes: drops the filter for that subtree
   - Result: cross-origin iframe renders unfiltered */

/* Same-origin iframes and page content: unaffected — filters still work */
/* Cross-origin iframes and plugins: filter is silently removed */

see also