CSS alone can steal passwords from your webmail
PortSwigger's Gareth Heyes turned a decade of CSS injection tricks into working account takeovers on Outlook, Gmail and more.
Every webmail client on earth makes the same bet: strip the dangerous bits out of an email's HTML, allow the styling, and let CSS render. Style is cosmetic. Scripts are the threat. That bet has been quietly wrong for years, and PortSwigger's Gareth Heyes just cashed it in — working account takeovers on Outlook, Gmail, Fastmail, Proton Mail, Yahoo and AOL using nothing but HTML and CSS. No JavaScript. No attachments. No payload the sanitizer was ever asked to catch.
If you build anything that renders untrusted HTML, this is your problem too, and the framing that matters isn't "audit your marketing templates." It's this: CSS allowlisting is a losing game the moment the browser mutates what you allowlisted, and the arrival of AI assistants reading your inbox just turned a decade of parlor tricks into a live exfiltration channel.
The trick isn't new. The chaining is.
CSS-only attacks are old news to anyone who's watched this space. Attribute-selector keyloggers that leak <input value> characters one background-image request at a time date back to 2018. Font-based exfiltration oracles, scroll-driven side channels, :has() and :checked state machines — the primitives have existed for years, dismissed as clever CTF fodder because real apps sandbox untrusted markup.
Webmail doesn't get to sandbox everything, because users demand rich formatting. So it sanitizes instead. And Heyes's real contribution is showing that the gap between what a sanitizer approves and what a browser actually executes is wide enough to drive an account takeover through.
The cleanest example: a sanitizer inspects a CSS string, decides it's safe, and passes it on. The browser then parses that same string into the CSSOM, and in doing so rewrites it — collapsing hex escapes like \5c into new characters, resolving image-set() fallbacks the validator never evaluated, reinterpreting media queries. The bytes the sanitizer blessed are not the bytes that run. Every prefix check, every allowlist, every "we strip url()" reassurance is defeated not by a bypass string but by the parser downstream of the check mutating benign input into hostile output.
Layered on top are what Heyes calls CSS gadgets: the webmail app's own JavaScript helpfully converts sanitized custom attributes into fresh DOM nodes that carry styling past the allowlist. The attacker never runs code. The victim's client runs it for them.
What actually falls over
The attack chains are specific and nasty:
- Outlook credential theft. A media-query parsing quirk grants arbitrary CSS, which is used to disguise a
<select>element as a password field and, in a Firefox chain, paint a pixel-perfect Microsoft sign-in screen inside the message. The recipient types their password into the email. - Yahoo/AOL token theft via paste. Pasted HTML briefly retains live CSS before sanitization fires — a race. Lure the victim into copying attacker CSS and pasting it into a draft, and enough of a 12-character Medium login token leaks for the server-side value to be reconstructed. Sign in as them.
- Cross-provider tracking. IP disclosure and read receipts on Proton Mail and Gmail via image-proxy bypasses, defeating the exact privacy protection those clients advertise.
The keyloggers deserve a note because they puncture the "CSS is passive" assumption entirely. A dictionary keylogger built from :has(), :checked and CSS animations fires a network request per matched keystroke. That is a functioning input-capture device written in a styling language.
The part that's genuinely new: AI reads the CSS you can't see
Here's where this stops being a webmail-vendor problem and becomes an everyone problem. AI email assistants read the raw DOM, including content that CSS has hidden from human eyes — opacity: 0, off-screen inset, ::before and ::after pseudo-elements. You see a bland newsletter. The model reads a completely different instruction underneath it.
Heyes demonstrated this against OpenAI's Atlas browser and, more pointedly, chained Gmail's image-set() bypass into indirect prompt injection through an Anthropic Cowork connector: trigger a Slack token-confirmation email, let the assistant process the hidden instructions, have it fetch the token and drop it into an HTML draft for exfiltration. The human approves a helpful-looking action. The token walks out the door.
This is the load-bearing insight for developers wiring LLMs to inboxes right now: CSS-hidden content is a first-class prompt-injection surface, and none of your existing "we sanitize HTML" hygiene touches it, because from the sanitizer's view that text is legitimate. Visual hiding is not semantic removal, and the model doesn't have eyes.
What to actually do
Skip the allowlist-tightening reflex — this research is a monument to why it fails. The defensible positions:
- Render untrusted email in a sandboxed iframe with a restrictive CSP, no
data:URLs, and images blocked or hard-proxied. Isolation beats enumeration. You cannot allowlist your way out of a parser you don't control. - If an LLM reads user-supplied HTML, strip or neutralize visually-hidden content before the model sees it — zero-opacity, off-viewport, and pseudo-element text. Feed the assistant what the human sees, not what the DOM contains.
- Treat CSS as executable.
:has(),:checked,:focus,<select>, and animations are control flow, not decoration. Drop them from anything untrusted.
Vendor response was uneven, which tells you how seriously to take your own exposure. Fastmail patched two mutation bugs and its proxy bypass; Proton Mail's bypass had stopped working on retest. But at publication on August 6, Outlook's label-jacking and Gmail's image-set() bypass still worked. The clients most of your users live in were still vulnerable when the research went public.
The takeaway isn't that CSS became dangerous. It's that "it's just styling" was never true, and the AI layer we're bolting onto email removed the last thing keeping the danger theoretical: a human in the loop who could see the trap.
Sources & further reading
- CSS: The bomb inside your inbox — portswigger.net
- New CSS Attacks Can Break Webmail Defenses to Steal Passwords and Tokens — thehackernews.com
- Webmail CSS Attacks Expose a New Risk for AI-Powered Email Tools — securityaffairs.com
Ji-ho covers the increasingly tangled overlap between cloud architecture and security, drawing on a background as a penetration tester to keep his reporting grounded in real-world attack paths. He never lets a vendor claim go unquestioned and insists that every buzzword come with a proof of concept.
Discussion 0
No comments yet
Be the first to weigh in.