PhoenixKit.Utils.CssValue (phoenix_kit v2.2.0)

Copy Markdown View Source

Allowlist validation for operator-supplied values that are embedded in CSS.

A settings field that ends up inside a stylesheet is not ordinary text: the surrounding <style> element is parsed as raw character data, so HTML escaping does not apply there and a value carrying </style> closes the element and starts a new one. That turned the auth-page background colour — a free-text field reachable by any holder of the settings permission — into stored XSS served to every anonymous visitor of the login page.

Both functions here are allowlists that fail to "", not sanitisers that attempt repair. A value that is not recognisably a colour or a URL is dropped entirely, because guessing at what an unrecognised value meant is how filters get bypassed.

Usage

iex> PhoenixKit.Utils.CssValue.color("#1e293b")
"#1e293b"

iex> PhoenixKit.Utils.CssValue.color("linear-gradient(135deg, #667eea 0%, #764ba2 100%)")
"linear-gradient(135deg, #667eea 0%, #764ba2 100%)"

iex> PhoenixKit.Utils.CssValue.color("red; } </style><script>alert(1)</script>")
""

iex> PhoenixKit.Utils.CssValue.url("/file/018e/original/ab12")
"/file/018e/original/ab12"

iex> PhoenixKit.Utils.CssValue.url("x'); } </style><script>alert(1)</script>")
""

Summary

Functions

Returns value when it is a safe CSS colour, colour function or gradient, otherwise "".

Returns value when it is safe to place inside a CSS url('…') token, otherwise "".

Functions

color(value)

@spec color(term()) :: String.t()

Returns value when it is a safe CSS colour, colour function or gradient, otherwise "".

Accepts what the background-colour setting is actually for — hex colours, rgb() / rgba() / hsl() / hsla(), CSS named colours, and linear-gradient() / radial-gradient() — and refuses everything else.

url(value)

@spec url(term()) :: String.t()

Returns value when it is safe to place inside a CSS url('…') token, otherwise "".

Only same-origin absolute paths and http/https URLs are accepted. The application generates these from a stored file uuid, so this is a guard against a malformed or crafted uuid reaching the stylesheet, not against an operator typing a URL.