Agent Wranglers

CSS-35Required

Keep untrusted data out of stylesheets

Pass user or third-party data to CSS only as the value of a custom property your code names, after it matches a fixed pattern. Such data never chooses a property, a selector or a whole declaration, and never reaches a url().

How to do it

A stylesheet can read a page without any script. An attribute selector such as input[value^="a"] with a background image sends each guessed character of a field to another server. So a user theme or a profile field never goes into a <style> element, a style attribute or a generated stylesheet. Match the value against a pattern first, such as ^#[0-9a-f]{6}$ or a number within a range. Then hand it over with setProperty('--profile-card-accent', value), as Write styles only in stylesheets describes. Reject anything else instead of trying to escape it. Values that hold a link also pass the URL checks in Escape everything you show.

Examples

JavaScript example

const ACCENT = /^#[0-9a-f]{6}$/i;

export function applyProfileAccent(card, accent) {
  if (!ACCENT.test(accent)) throw new Error('accent must be a six-digit hex value');
  card.style.setProperty('--profile-card-accent', accent);
}

Python example

import re

ACCENT = re.compile(r"#[0-9a-fA-F]{6}")

def save_profile_accent(profile, accent: str) -> None:
    if not ACCENT.fullmatch(accent):
        raise ValueError("accent must be a six-digit hex value")
    profile.accent = accent

How to check

A unit test passes red;background:url(https://evil.example/) and }body{display:none to every function that hands data to CSS. Each call throws, and no url( reaches the page. A search of the templates finds 0 template expressions inside <style> elements or style attributes.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/html-css/structure-and-files/untrusted-data-in-css">Agent Wranglers HTML and CSS playbook</a>. In code you write, add a comment next to it with the same link.