Sep 8, 2026·7 min read·5 visits
SWC HTML minifier incorrectly converts safe Unicode-escaped less-than characters inside JSON blocks to raw less-than characters, allowing attackers to terminate script blocks early and execute arbitrary JavaScript (XSS) in victim browsers.
CVE-2026-72925 is a critical vulnerability in the SWC HTML minifier (@swc/html and swc_html_minifier) where safe Unicode-escaped characters in embedded JSON script tags are normalized into raw, unescaped characters during optimization, causing browser-side HTML injection and Cross-Site Scripting.
The @swc/html package and the underlying Rust-based swc_html_minifier crate are utilized within high-performance frontend build pipelines to compile, optimize, and minify HTML templates and static pages. To maximize execution speed, the Speedy Web Compiler (SWC) architecture parses the entire HTML document object model (DOM) into an Abstract Syntax Tree (AST), optimizes each node, and serializes the tree back into a minified string. This minification pipeline exposes a critical attack surface when handling structured metadata inside non-executable script tags.\n\nWeb applications commonly embed structured data using tags such as <script type="application/json"> or <script type="application/ld+json">. While browsers do not directly execute these blocks as scripts, the HTML parser still processes the containing text block under specific state rules. A vulnerability arises if the compiler's minification engine fails to preserve safety guarantees implemented by upstream application layers during the serialization of these embedded JSON payloads.\n\nCVE-2026-72925 describes an improper encoding vulnerability where safe Unicode-escaped sequences (such as \\u003C) are normalized into raw ASCII characters during the re-serialization of JSON blocks. Because the HTML parser evaluates the raw characters before the JSON is parsed, this normalization breaks the script container boundary, introducing an unauthenticated Cross-Site Scripting (XSS) vector. This analysis dissects the technical mechanics of the bug, the exact code-level failure, and the remediation path.
To understand the root cause of CVE-2026-72925, one must examine how web browsers parse script elements under the HTML5 standard. When the browser's tokenization engine encounters a <script> tag, it transitions into the Script Data State. In this state, the parser stops interpreting typical HTML markup, including elements, tags, and comments. It treats all characters as raw text until it matches an end tag open token (</) followed by the exact token sequence script (case-insensitive).\n\nThis behavior remains active even if the script tag's MIME type indicates non-executable data, such as application/json or application/ld+json. If a JSON block within a script tag contains a string like </script>, the parser interprets this string as the literal termination of the script block. To prevent this, secure application frameworks escape the less-than character as a Unicode escape sequence (\\u003C) when serializing JSON for inclusion in HTML documents. The browser's HTML parser reads \\u003C as a plain string, keeping the script block intact.\n\nIn vulnerable versions of swc_html_minifier, the JSON parser deserializes the embedded JSON payload to minify its structure, removing redundant whitespace and formatting. During the subsequent serialization step, the underlying JSON serializer normalizes the safe \\u003C representation back to its raw ASCII character <. Because this raw character is written directly into the final HTML token stream, the browser's parser encounters </script> as a literal element boundary rather than an escaped JSON string value.
The vulnerability in swc_html_minifier resides in how the compiler processes script blocks designated as JSON containers. Prior to the fix, the compiler minified the JSON string and assigned the serialized output directly to the node data without post-processing. The following diff highlights the implementation of the fix within crates/swc_html_minifier/src/lib.rs under commit e1877b44bdac8abc9fd51e984d584f40f6999832.\n\nrust\n// Crates: swc_html_minifier\n// File: crates/swc_html_minifier/src/lib.rs\n\nimpl<C: MinifyCss> Minifier<'_, C> {\n // ... existing code ...\n\n+ /// Escapes serialized JSON so it cannot terminate its containing HTML\n+ /// `script` element.\n+ ///\n+ /// HTML tokenization recognizes `</script` before the JSON is parsed.\n+ /// Serializing an escaped `<` as a literal character can therefore turn\n+ /// JSON data into a different HTML element structure.\n+ fn escape_json_for_html_script(json: String) -> String {\n+ if json.contains('<') {\n+ json.replace('<', "\\\\u003C")\n+ } else {\n+ json\n+ }\n+ }\n\n fn need_minify_js(&self) -> bool {\n // ...\n\n\nDuring the AST traversal, the minifier visits the script nodes and performs the minimization. The patch intercepts the assignment of the minified string, ensuring that any literal < character is re-escaped before writeback:\n\nrust\nimpl<C: MinifyCss> VisitMut for Minifier<'_, C> {\n // ... inside the AST visit loop for script elements ...\n Some(MinifierType::Json) => {\n let minified =\n match self.minify_json(&n.data) {\n Some(v) => v,\n None => return,\n };\n\n- n.data = minified.into();\n+ n.data = Self::escape_json_for_html_script(minified).into();\n }\n\n\nThis fix successfully blocks the primary vector by replacing all raw < characters with their Unicode escape sequences (\\u003C). However, because it performs a simple string replacement after serialization, it relies heavily on the correctness of the preceding JSON parsing stages. If the incoming JSON payload is malformed in a way that escapes normal parsing but triggers the replacement logic incorrectly, parser differentials could still manifest, though no such variants are currently known.
Exploitation of CVE-2026-72925 requires that an attacker can inject arbitrary strings into a data field that is later embedded in an application's JSON configuration and processed by a vulnerable SWC build pipeline. The attacker does not need direct access to the build server; the exploit payload is compiled statically or dynamically into the application's client-facing assets. The primary prerequisite is that the backend application must serialize the payload into an embedded JSON script tag.\n\nmermaid\ngraph LR\n A["Attacker Input"] -->|"\u003C/script><script>alert(1)</script>"| B["Backend Server"]\n B -->|"Serializes HTML safely"| C["Safe HTML template"]\n C -->|"\u003C/script> safe Unicode"| D["Vulnerable SWC Minifier"]\n D -->|"Normalizes to raw </script>"| E["Compiles Unsafe HTML"]\n E -->|"Delivers Payload"| F["Victim Browser"]\n F -->|"Executes Script"| G["XSS Execution"]\n\n\nConsider a user profile configuration where a user can supply a custom configuration object. The backend properly sanitizes the database output, escaping the JSON to prevent immediate XSS. This produces the following safe HTML markup before minification:\n\nhtml\n<script type="application/json">\n {\n "theme": "dark",\n "custom_label": "\\u003C/script><script>alert(document.domain)</script>"\n }\n</script>\n\n\nWhen the vulnerable version of @swc/html processes this template, the serialization output normalizes the Unicode escape sequence. The resulting minified HTML contains a raw < character within the JSON string:\n\nhtml\n<script type=application/json>{"theme":"dark","custom_label":"</script><script>alert(document.domain)</script>"}</script>\n\n\nWhen the victim's browser loads the page, the HTML parser parses the script tag up to the first occurrence of </script>. It immediately closes the script context and treats the subsequent characters <script>alert(document.domain)</script> as a new, active executable script block. The browser then executes the arbitrary JavaScript in the context of the vulnerable application's origin.
The impact of CVE-2026-72925 is high-severity Cross-Site Scripting (XSS). An attacker who successfully exploits this vulnerability can execute arbitrary JavaScript code within the context of the victim's browser session. Depending on the design of the target web application, this execution can lead to the theft of session tokens, sensitive user data, and automated actions on behalf of the victim.\n\nThe CVSS v3.1 score of 6.1 (Medium) reflects the standard constraints of client-side exploitation. The attack vector is Network (AV:N), and complexity is Low (AC:L) since the exploit does not require specialized conditions. No privileges are required (PR:N) for the initial payload injection if the data-entry path is public. However, User Interaction (UI:R) is required because a victim must load the minified HTML asset in their browser. The Scope is Changed (S:C) because the vulnerability in the static compilation pipeline affects the browser execution environment.\n\nAccording to current intelligence, the EPSS score is 0.00194, indicating a very low current probability of automated exploit campaigns in the wild. The vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, because build tools are often integrated into continuous delivery (CI/CD) pipelines, vulnerabilities of this class can propagate rapidly to multiple production servers once a compromised source branch is merged.
The primary remediation strategy is upgrading the SWC packages across all development and production environments. For Node.js-based environments, update the @swc/html dependency to version 1.15.47 or later. For Rust projects, update the swc crate to version 1.15.47 or later, and the swc_html_minifier crate to version 59.0.0 or later.\n\nTo identify vulnerable configurations programmatically, security teams can implement automated dependency scanning to detect out-of-date SWC packages in lockfiles. A manual verification can also be performed by compiling a test file. Create a file named test.html containing the following text:\n\nhtml\n<script type="application/json">{"test":"\\u003C/script>"}</script>\n\n\nCompile the file using your current SWC build configuration. If the output contains the raw string </script> inside the JSON object, the pipeline is vulnerable. If the output preserves \\u003C/script>, the fix is active. In environments where upgrading is not immediately possible, deploy a Web Application Firewall (WAF) rule to block or sanitize input payloads containing closing HTML tags inside JSON-like request structures.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@swc/html swc-project | < 1.15.47 | 1.15.47 |
swc swc-project | < 1.15.47 | 1.15.47 |
swc_html_minifier swc-project | < 59.0.0 | 59.0.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-79 (Improper Neutralization of Input During Web Page Generation) |
| Attack Vector | Network (AV:N/AC:L/PR:N/UI:R) |
| CVSS v3.1 Score | 6.1 (Medium) |
| EPSS Score | 0.00194 (Percentile: 9.11%) |
| Impact | Stored / DOM-based Cross-Site Scripting (XSS) |
| Exploit Status | Conceptual Proof-of-Concept |
| KEV Status | Not Listed |
The software does not neutralize or incorrectly neutralizes user-controlled input before displaying it in a web browser, allowing scripts to be executed.
A command-line option injection vulnerability in GitPython allows low-privilege or unauthenticated actors to read arbitrary local files. The flaw resides in the TagReference.create() function, which fails to evaluate positional arguments against the library's unsafe-option denylist, enabling the execution of native git commands with injected option flags.
GitPython prior to version 3.1.59 contains a path traversal vulnerability via parameter injection. The clone denylist did not restrict the `--separate-git-dir` option, allowing attackers to write repository metadata to arbitrary system paths.
A critical logical flaw in the Natural Language Toolkit (NLTK) allows attackers to bypass the application-level directory sandbox. This vulnerability enables unauthenticated directory enumeration and arbitrary local file or SQLite database access.
An improper integrity verification vulnerability exists in the Natural Language Toolkit (NLTK) library up to and including version 3.9.4. The library's download utility writes remote ZIP packages directly to disk and extracts their contents onto the filesystem before executing cryptographic checksum validation. An attacker capable of intercepting or manipulating the download stream can exploit this behavior to perform arbitrary file writes, directory traversal, or execute untrusted serialized content.
A critical Server-Side Request Forgery (SSRF) bypass vulnerability exists in CodeWhale before version 0.8.64 (and version 0.8.41 in the 0.8.x branch) due to a Time-of-Check to Time-of-Use (TOCTOU) bug in its DNS pre-flight validation mechanism. By returning a temporary resolution failure during validation and subsequently resolving to restricted IPs during HTTP execution, attackers can bypass security rules.
An argument injection vulnerability in CodeWhale (CVE-2026-75912 / GHSA-c6mw-8xh8-gpq6) allows unauthenticated remote attackers to execute arbitrary option commands on the git binary. By passing malicious command-line flags inside git_blame and git_show tool helper functions, an attacker can bypass typical access controls to read arbitrary local system files via the underlying git process.