Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-50290

CVE-2026-50290: SpecifyJS CSS Injection XSS Vulnerability

CVE-2026-50290 is a CSS injection XSS vulnerability in SpecifyJS that allowed attackers to bypass CSS sanitization using unicode escapes and comments. This post explains its impact, affected versions, and mitigation steps.

Published:

CVE-2026-50290 Overview

CVE-2026-50290 is a cross-site scripting (XSS) vulnerability [CWE-79] in SpecifyJS, a declarative TypeScript user interface framework. Versions prior to 0.2.136 implement CSS value sanitization using simple regex patterns that strip expression( and url(javascript: substrings. Attackers can bypass this filter using CSS unicode escapes such as \65xpression(, null bytes, or inline CSS comments like exp/**/ression(. The bypass only affects legacy browsers (Internet Explorer 6 through 10), and SpecifyJS targets modern browsers, which limits real-world impact.

Critical Impact

CSS injection payloads can evade sanitization in legacy browser contexts, enabling script execution through CSS expression() and related legacy vectors.

Affected Products

  • SpecifyJS versions prior to 0.2.136
  • Applications rendering user-controlled CSS values through SpecifyJS server-side rendering
  • Legacy browser clients (IE6–IE10) consuming SpecifyJS-rendered output

Discovery Timeline

  • 2026-08-21 - CVE-2026-50290 published to NVD
  • 2026-08-21 - Last updated in NVD database

Technical Details for CVE-2026-50290

Vulnerability Analysis

The vulnerability resides in the CSS sanitization logic in core/src/server/render-to-string.ts. The original implementation applied two regex substitutions to strip expression( and url(javascript: from CSS values. This pattern-matching approach operates on the raw input string without normalization. Attackers can construct payloads that decode to the dangerous tokens only after the CSS parser interprets escape sequences or comments.

CSS parsers in legacy browsers resolve unicode escapes like \65 to the character e before tokenization. A payload of \65xpression(alert(1)) bypasses a naive regex looking for the literal string expression(. Similarly, CSS comments /* */ are stripped by the parser but preserved by the sanitizer, allowing exp/**/ression( to slip through. Null byte insertion produces the same bypass class.

Root Cause

The root cause is incomplete input canonicalization. The sanitizer matched patterns against the untransformed input while the CSS parser evaluates a canonicalized form. This mismatch between the sanitizer's view and the parser's view of the input is a classic filter-bypass pattern.

Attack Vector

An attacker supplies a crafted CSS value through any interface where SpecifyJS accepts user-controlled style properties. The malicious value passes the regex filter, is embedded in the rendered output, and executes when a legacy browser evaluates the CSS expression(), behavior:, -moz-binding, or -o-link construct. User interaction is required to load the page.

typescript
// Patch from core/src/server/render-to-string.ts
// Before: naive substring stripping
// cssValue = cssValue
//   .replace(/expression\s*\(/gi, '')
//   .replace(/url\s*\(\s*javascript:/gi, 'url(');

// After: normalize then reject
const normalizedCss = cssValue
  .replace(/\\[0-9a-fA-F]{1,6}\s?/g, '_')
  .replace(/\/\*[\s\S]*?\*\//g, '');
if (/expression\s*\(|javascript\s*:|behavior\s*:|moz-binding|-o-link/i.test(normalizedCss)) {
  cssValue = '';
}

Source: GitHub Commit 25d1fb4

Detection Methods for CVE-2026-50290

Indicators of Compromise

  • CSS property values containing backslash-hex escape sequences such as \65, \45, or \75 followed by identifier characters
  • CSS values containing inline C-style comments (/* */) inside property tokens
  • Rendered HTML style attributes containing the substrings behavior:, -moz-binding, -o-link, or expression(
  • Requests carrying null bytes (%00) inside CSS parameter values

Detection Strategies

  • Inspect HTTP request bodies and query parameters for CSS unicode escape patterns matching \\[0-9a-fA-F]{1,6} inside style-bearing fields
  • Scan server-rendered HTML output for CSS keywords that should never appear in sanitized output, including expression, behavior, and moz-binding
  • Enable Content Security Policy reporting to catch inline style evaluation attempts in downstream clients

Monitoring Recommendations

  • Log all SpecifyJS render calls that consume externally sourced style values and forward them to a centralized analytics pipeline
  • Alert on outbound responses containing legacy CSS execution keywords after sanitization has run
  • Track SpecifyJS package versions across deployments to identify hosts still running versions below 0.2.136

How to Mitigate CVE-2026-50290

Immediate Actions Required

  • Upgrade SpecifyJS to version 0.2.136 or later across all affected applications
  • Audit application code for user-controlled inputs flowing into SpecifyJS style properties
  • Enforce a strict Content Security Policy that disallows inline styles and unsafe expressions

Patch Information

The fix is included in SpecifyJS 0.2.136 and documented in GitHub Security Advisory GHSA-93q6-wwjh-jc6h. The updated sanitizer normalizes unicode escapes and strips CSS comments before pattern matching, and it rejects behavior:, -moz-binding, and -o-link in addition to expression( and javascript:. The corresponding code change is available in commit 25d1fb4.

Workarounds

  • Reject any style attribute values containing backslash characters at the application input layer
  • Deploy a Content Security Policy header that blocks legacy CSS execution vectors
  • Block or upgrade legacy browsers (IE6–IE10) that honor the affected CSS constructs
bash
# Upgrade to patched version
npm install specifyjs@0.2.136

# Verify installed version
npm ls specifyjs

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.