The vulnerability is a stored Cross-Site Scripting (XSS) issue in ApostropheCMS, originating from the @apostrophecms/color-field module. The root cause is a two-part problem involving both improper input validation and a lack of output escaping.
First, the convert function within the @apostrophecms/color-field module intentionally bypasses validation for any string starting with --. This was intended to allow the use of CSS custom properties (variables), but it failed to sanitize the rest of the string. This allowed an editor to save a malicious payload, such as --x: red}</style><script>alert(document.cookie)</script><style>, into a color field. The system would store this payload in the database.
Second, when rendering pages, ApostropheCMS uses this stored value in two vulnerable ways:
- The
getWidgetElements function in the @apostrophecms/styles module injects per-widget styles directly into a <style> tag on the public-facing page. It did not escape the CSS content, allowing the injected </style> tag from the payload to close the style block prematurely and execute arbitrary JavaScript. This affects all site visitors.
- The
getHeadNodes function, also in @apostrophecms/styles, prepares the global stylesheet for authenticated users viewing draft pages. It placed the malicious payload into a raw node that the template engine would render unescaped, leading to XSS and potential session hijacking of higher-privileged users like administrators.
The patch addresses these issues by adding strict validation in the convert function to only allow valid CSS variable syntax and by adding output escaping in both getWidgetElements and getHeadNodes to neutralize any remaining malicious characters before rendering.