CVE-2023-26119
Description
Versions of the package net.sourceforge.htmlunit:htmlunit from 0 and before 3.0.0 are vulnerable to Remote Code Execution (RCE) via XSTL, when browsing the attacker’s webpage.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
HtmlUnit before 3.0.0 allows remote code execution via XSLT when a user visits a malicious webpage, due to missing secure processing features.
The vulnerability stems from the XSLT processor in HtmlUnit not enabling FEATURE_SECURE_PROCESSING, allowing untrusted XSLT stylesheets to execute arbitrary Java code via Xalan extensions [3][4].
An attacker can host a webpage containing malicious XSLT that, when browsed by an HtmlUnit WebClient, triggers the execution of arbitrary commands on the host system [4]. No authentication is required; the victim simply needs to load the attacker's page.
Successful exploitation grants the attacker full remote code execution with the privileges of the HtmlUnit process, potentially leading to complete compromise of the application or server using HtmlUnit [1].
The issue is fixed in HtmlUnit 3.0.0 by enabling FEATURE_SECURE_PROCESSING in the XSLT processor [3]. Users should upgrade to version 3.0.0 or later. No workaround is available for earlier versions.
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
net.sourceforge.htmlunit:htmlunitMaven | < 3.0.0 | 3.0.0 |
Affected products
3Patches
1641325bbc847enable FEATURE_SECURE_PROCESSING for the XSLT processor
4 files changed · +113 −13
src/changes/changes.xml+3 −0 modified@@ -8,6 +8,9 @@ <body> <release version="2.70.0" date="Febuary xx, 2023" description="Bugfixes"> + <action type="fix" dev="rbri"> + Enable FEATURE_SECURE_PROCESSING for the XSLT processor. + </action> <action type="add" dev="rbri"> Document disabling of website certificate check in the FAQ. </action>
src/main/java/com/gargoylesoftware/htmlunit/javascript/host/xml/XSLTProcessor.java+6 −0 modified@@ -26,6 +26,7 @@ import java.util.HashMap; import java.util.Map; +import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; @@ -128,6 +129,11 @@ private Object transform(final Node source) { final TransformerFactory transformerFactory = TransformerFactory.newInstance(); + // By default, the JDK turns on FSP for DOM and SAX parsers and XML schema validators, + // which sets a number of processing limits on the processors. Conversely, by default, + // the JDK turns off FSP for transformers and XPath, which enables extension functions for XSLT and XPath. + transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + final SgmlPage page = sourceDomNode.getPage(); if (page != null && page.getWebClient().getBrowserVersion() .hasFeature(JS_XSLT_TRANSFORM_INDENT)) {
src/test/java/com/gargoylesoftware/htmlunit/ErrorOutputChecker.java+6 −1 modified@@ -47,7 +47,12 @@ public class ErrorOutputChecker implements MethodRule { // Quercus Pattern.compile(".*com.caucho.quercus.servlet.QuercusServlet initImpl\r?\n"), Pattern.compile(".*QuercusServlet starting as QuercusServletImpl\r?\n"), - Pattern.compile(".*Quercus finished initialization in \\d*ms\r?\n") + Pattern.compile(".*Quercus finished initialization in \\d*ms\r?\n"), + + // Xalan + Pattern.compile("ERROR:\\s*'Use of the extension function " + + "'http://xml\\.apache\\.org/xalan/java/.*' " + + "is not allowed when the secure processing feature is set to true\\.'\r?\n"), }; /**
src/test/java/com/gargoylesoftware/htmlunit/javascript/host/xml/XSLTProcessorTest.java+98 −12 modified@@ -23,6 +23,7 @@ import com.gargoylesoftware.htmlunit.WebDriverTestCase; import com.gargoylesoftware.htmlunit.junit.BrowserRunner; import com.gargoylesoftware.htmlunit.junit.BrowserRunner.Alerts; +import com.gargoylesoftware.htmlunit.junit.BrowserRunner.HtmlUnitNYI; import com.gargoylesoftware.htmlunit.util.MimeType; /** @@ -38,28 +39,49 @@ public class XSLTProcessorTest extends WebDriverTestCase { * @throws Exception if the test fails */ @Test - @Alerts("exception") + @Alerts(DEFAULT = "<html xmlns=\"http://www.w3.org/1999/xhtml\">" + + "<head></head><body> <h2>My CD Collection</h2> " + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul> </body></html>", + FF = "<html xmlns=\"http://www.w3.org/1999/xhtml\">" + + "<body><h2>My CD Collection</h2>" + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>", + FF_ESR = "<html xmlns=\"http://www.w3.org/1999/xhtml\">" + + "<body><h2>My CD Collection</h2>" + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>", + IE = "exception") + @HtmlUnitNYI(CHROME = "<html><body><h2>My CD Collection</h2>" + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>", + EDGE = "<html><body><h2>My CD Collection</h2>" + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>", + FF = "<html><body><h2>My CD Collection</h2>" + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>", + FF_ESR = "<html><body><h2>My CD Collection</h2>" + + "<ul><li>Empire Burlesque (Bob Dylan)</li></ul></body></html>") public void test() throws Exception { final String html = "<html><head>\n" + "<script>\n" + LOG_TITLE_FUNCTION + + + " function createXmlDocument() {\n" + + " return document.implementation.createDocument('', '', null);\n" + + " }\n" + + + " function loadXMLDocument(url) {\n" + + " var xhttp = new XMLHttpRequest();\n" + + " xhttp.open('GET', url, false);\n" + + " xhttp.send();\n" + + " return xhttp.responseXML;\n" + + " }" + + " function test() {\n" + " try {\n" - + " var xmlDoc = createXmlDocument();\n" - + " xmlDoc.async = false;\n" - + " xmlDoc.load('" + URL_SECOND + "1');\n" - - + " var xslDoc;\n" - + " xslDoc = createXmlDocument();\n" - + " xslDoc.async = false;\n" - + " xslDoc.load('" + URL_SECOND + "2');\n" + + " var xmlDoc = loadXMLDocument('" + URL_SECOND + "1');\n" + + " var xslDoc = loadXMLDocument('" + URL_SECOND + "2');\n" + " var processor = new XSLTProcessor();\n" + " processor.importStylesheet(xslDoc);\n" + " var newDocument = processor.transformToDocument(xmlDoc);\n" - + " log(new XMLSerializer().serializeToString(newDocument.documentElement).length);\n" - + " newDocument = processor.transformToDocument(xmlDoc.documentElement);\n" - + " log(newDocument.documentElement);\n" + + " log(new XMLSerializer().serializeToString(newDocument.documentElement));\n" + " } catch(e) { log('exception'); }\n" + " }\n" @@ -199,4 +221,68 @@ public void browserDetection() throws Exception { + "</body></html>"; loadPageVerifyTitle2(html); } + + /** + * @throws Exception if the test fails + */ + @Test + @Alerts(DEFAULT = {"preparation done", "null"}, + FF = {"preparation done", "exception"}, + FF_ESR = {"preparation done", "exception"}, + IE = "exception") + @HtmlUnitNYI(CHROME = {"preparation done", "exception"}, + EDGE = {"preparation done", "exception"}) + public void testSecurity() throws Exception { + final String html = "<html><head>\n" + + "<script>\n" + + LOG_TITLE_FUNCTION + + + " function createXmlDocument() {\n" + + " return document.implementation.createDocument('', '', null);\n" + + " }\n" + + + " function loadXMLDocument(url) {\n" + + " var xhttp = new XMLHttpRequest();\n" + + " xhttp.open('GET', url, false);\n" + + " xhttp.send();\n" + + " return xhttp.responseXML;\n" + + " }" + + + " function test() {\n" + + " try {\n" + + " var xmlDoc = loadXMLDocument('" + URL_SECOND + "1');\n" + + " var xslDoc = loadXMLDocument('" + URL_SECOND + "2');\n" + + + " var processor = new XSLTProcessor();\n" + + " processor.importStylesheet(xslDoc);\n" + + " log('preparation done');\n" + + " var newDocument = processor.transformToDocument(xmlDoc);\n" + + " log(newDocument);\n" + + " } catch(e) { log('exception'); }\n" + + " }\n" + + "</script></head>" + + "<body onload='test()'>\n" + + "</body></html>"; + + final String xml + = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" + + "<s></s>"; + + final String xsl + = " <xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " + + "xmlns:rt=\"http://xml.apache.org/xalan/java/java.lang.Runtime\" " + + "xmlns:ob=\"http://xml.apache.org/xalan/java/java.lang.Object\">\r\n" + + " <xsl:template match='/'>\n" + + " <xsl:variable name='rtobject' select='rt:getRuntime()'/>\n" + + " <xsl:variable name=\"rtString\" select=\"ob:toString($rtobject)\"/>\n" + + " <xsl:value-of select=\"$rtString\"/>\n" + + " </xsl:template>\r\n" + + " </xsl:stylesheet>"; + + final MockWebConnection conn = getMockWebConnection(); + conn.setResponse(new URL(URL_SECOND, "1"), xml, MimeType.TEXT_XML); + conn.setResponse(new URL(URL_SECOND, "2"), xsl, MimeType.TEXT_XML); + + loadPageVerifyTitle2(html); + } }
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/advisories/GHSA-3xrr-7m6p-p7xhghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-26119ghsaADVISORY
- github.com/HtmlUnit/htmlunit/commit/641325bbc84702dc9800ec7037aec061ce21956bghsaWEB
- security.snyk.io/vuln/SNYK-JAVA-NETSOURCEFORGEHTMLUNIT-3252500ghsaWEB
- siebene.github.io/2022/12/30/HtmlUnit-RCEghsaWEB
- siebene.github.io/2022/12/30/HtmlUnit-RCE/mitre
News mentions
0No linked articles in our index yet.