CVE-2026-33889 Overview
ApostropheCMS, an open-source Node.js content management system, contains a stored cross-site scripting (XSS) vulnerability in the @apostrophecms/color-field module affecting versions 4.28.0 and prior. The vulnerability exists because color values prefixed with -- (CSS custom properties) bypass TinyColor validation, and the launder.string() function performs only type coercion without stripping HTML metacharacters. These unsanitized values are concatenated directly into <style> tags in both per-widget style elements rendered for all visitors and in the global stylesheet rendered for editors, with output marked as safe HTML.
Critical Impact
An editor can inject malicious values that close the style tag and execute arbitrary JavaScript in the browser of every visitor to any page containing the affected widget. This enables mass session hijacking, cookie theft, and privilege escalation to administrative control if an admin views draft content.
Affected Products
- ApostropheCMS versions 4.28.0 and prior
- @apostrophecms/color-field module
- @apostrophecms/styles module
Discovery Timeline
- 2026-04-15 - CVE CVE-2026-33889 published to NVD
- 2026-04-16 - Last updated in NVD database
Technical Details for CVE-2026-33889
Vulnerability Analysis
This stored XSS vulnerability stems from insufficient input validation in the color field handling logic. When users input color values beginning with -- (intended for CSS custom properties), the TinyColor validation library is bypassed entirely. The subsequent launder.string() function only performs type coercion and does not sanitize HTML metacharacters such as <, >, or /. The unsanitized user input is then directly concatenated into <style> elements that are marked as "safe HTML," meaning no additional escaping occurs during template rendering.
The attack is particularly dangerous because the malicious payload persists in the database and executes in multiple contexts: once in per-widget style elements rendered for all site visitors, and again in the global stylesheet rendered for authenticated editors. This dual exposure maximizes the attack surface and impact.
Root Cause
The root cause is twofold: first, the validation logic specifically exempts CSS custom property values (those starting with --) from TinyColor validation; second, there is no subsequent sanitization to strip or encode HTML metacharacters from these exempted values. The combination of bypassed validation and missing output encoding creates a direct path from user input to executable script context within <style> tags.
Attack Vector
An authenticated editor with access to the color field can craft a malicious input value that:
- Starts with -- to bypass TinyColor color validation
- Contains HTML metacharacters to close the <style> tag
- Injects a <script> tag with arbitrary JavaScript
When any visitor loads a page containing the affected widget, or when an administrator previews draft content, the injected JavaScript executes in their browser context with full access to cookies, session tokens, and DOM manipulation capabilities.
// Security patch in @apostrophecms/color-field/index.js
// Source: https://github.com/apostrophecms/apostrophe/commit/6a89bdb7acdb2e1e9bf1429961a6ba7f99410481
throw self.apos.error('required');
}
+ const isVariable = destination[field.name].startsWith('--');
const test = new TinyColor(destination[field.name]);
- if (!test.isValid && !destination[field.name].startsWith('--')) {
+ if (!test.isValid && !isVariable) {
destination[field.name] = null;
+ } else if (isVariable) {
+ // CSS custom property names: only allow alphanumeric, hyphens, underscores
+ if (!/^--[a-zA-Z0-9_-]+$/.test(destination[field.name])) {
+ destination[field.name] = null;
+ }
}
},
isEmpty: function (field, value) {
The patch adds strict regex validation for CSS custom property names, ensuring they contain only alphanumeric characters, hyphens, and underscores.
// Security patch in @apostrophecms/styles/lib/methods.js
// Source: https://github.com/apostrophecms/apostrophe/commit/6a89bdb7acdb2e1e9bf1429961a6ba7f99410481
});
}
if (!hasLink) {
+ // Prevent an XSS attack even if a styles exploit is found
+ const css = (req.data.global.stylesStylesheet || '').replaceAll('</', '<\\/');
nodes.push({
name: 'style',
attrs: {
id: 'apos-styles-stylesheet'
},
body: [
{
- raw: req.data.global.stylesStylesheet || ''
+ raw: css
}
]
});
This additional patch escapes closing tags within stylesheet content as a defense-in-depth measure.
Detection Methods for CVE-2026-33889
Indicators of Compromise
- Color field values in the database containing HTML tags or script elements
- Color values starting with -- followed by characters other than alphanumeric, hyphens, or underscores
- Unexpected <script> tags or JavaScript event handlers in rendered page source within <style> elements
- User reports of browser security warnings or unexpected redirects on CMS pages
Detection Strategies
- Implement Content Security Policy (CSP) headers to detect and block inline script execution attempts
- Monitor application logs for unusual color field input patterns, particularly values containing <, >, or script
- Deploy Web Application Firewall (WAF) rules to flag requests containing XSS payloads in form fields
- Conduct regular database audits of color field values for malicious content
Monitoring Recommendations
- Enable browser developer tools console monitoring in staging environments to catch CSP violations
- Implement real-time alerting for database writes to color field columns containing HTML metacharacters
- Configure server-side logging to capture full request bodies for content modification endpoints
- Review CMS audit logs for editor activity patterns that may indicate malicious intent
How to Mitigate CVE-2026-33889
Immediate Actions Required
- Upgrade ApostropheCMS to version 4.29.0 or later immediately
- Audit existing color field values in the database for any malicious content
- Implement Content Security Policy headers to mitigate impact of any existing stored payloads
- Review editor access permissions and limit color field editing to trusted users
Patch Information
The vulnerability has been fixed in ApostropheCMS version 4.29.0. The fix implements two layers of protection:
- Input validation: CSS custom property names are now validated against a strict regex pattern (/^--[a-zA-Z0-9_-]+$/) that only allows alphanumeric characters, hyphens, and underscores
- Output encoding: Closing tags within stylesheet content are escaped as a defense-in-depth measure
For detailed patch information, see the GitHub commit and GitHub Security Advisory GHSA-97v6-998m-fp4g.
Workarounds
- Temporarily disable the @apostrophecms/color-field module if not essential to site functionality
- Restrict editor permissions to prevent untrusted users from modifying color field values
- Implement a server-side input validation middleware to sanitize color field values before database storage
- Deploy strict Content Security Policy headers including script-src 'self' to block inline script execution
# Configuration example - Add CSP headers to your Node.js/Express configuration
# This provides defense-in-depth against XSS exploitation
# In your Express app configuration:
app.use((req, res, next) => {
res.setHeader(
'Content-Security-Policy',
"default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:;"
);
next();
});
# Or via nginx configuration:
add_header Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" always;
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

