Cross-site Scripting in org.xwiki.commons:xwiki-commons-xml
Description
XWiki Commons restricted HTML cleaner mode allows injection of arbitrary HTML via invalid comments, leading to stored XSS and potential server-side code execution.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
XWiki Commons restricted HTML cleaner mode allows injection of arbitrary HTML via invalid comments, leading to stored XSS and potential server-side code execution.
Vulnerability
Description
The vulnerability resides in the "restricted" mode of the HTML cleaner in XWiki Commons, introduced in version 4.2-milestone-1 and improved in version 14.6-rc-1. The cleaner did not properly handle invalid HTML comments, allowing an attacker to inject arbitrary HTML code. Specifically, comments starting with > or containing --> could bypass sanitization, leading to cross-site scripting (XSS) [1][2][4].
Exploitation
To exploit, an attacker can inject a crafted HTML comment in user input that is processed by the restricted mode. For example, an anonymous comment containing <!--> would be rendered unsanitized. When a privileged user with programming rights visits this comment, the malicious JavaScript executes in their session context [1][4].
Impact
Successful exploitation allows an attacker to execute arbitrary JavaScript in the victim's browser. Since the victim has programming rights, the attacker can perform server-side operations with those privileges, compromising confidentiality, integrity, and availability of the XWiki instance [1][4].
Mitigation
The issue is patched in XWiki 14.10. The fix removes HTML comments entirely in restricted mode and adds a check to ensure comment text does not start with > [2][4]. No workarounds are available; upgrading is required.
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 |
|---|---|---|
org.xwiki.commons:xwiki-commons-xmlMaven | >= 4.2-milestone-1, < 14.10 | 14.10 |
Affected products
2- Range: >= 4.2-milestone-1, < 14.10
Patches
18ff1a9d7e5d7XCOMMONS-2568: Improve comment handling in HTMLCleaner (#306)
3 files changed · +75 −2
xwiki-commons-core/xwiki-commons-xml/src/main/java/org/xwiki/xml/html/HTMLUtils.java+17 −0 modified@@ -26,6 +26,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.jdom.Comment; import org.jdom.DocType; import org.jdom.Element; import org.jdom.input.DOMBuilder; @@ -179,6 +180,22 @@ protected void printElement(Writer out, Element element, int level, NamespaceSta currentFormat.setExpandEmptyElements(currentFormatPolicy); } } + + @Override + protected void printComment(Writer out, Comment comment) throws IOException + { + String commentText = comment.getText(); + + // TODO: remove this again when https://sourceforge.net/p/htmlcleaner/bugs/234/ has been fixed. + // Make sure that the comment text conforms to the HTML specification, in particular: "Optionally, text, + // with the additional restriction that the text must not start with the string ">", nor start with the + // string "->", nor contain the strings "<!--", "-->", or "--!>", nor end with the string "<!-"." + while (commentText.startsWith(">") || commentText.startsWith("->")) { + commentText = commentText.substring(1); + } + + super.printComment(out, new Comment(commentText)); + } } /**
xwiki-commons-core/xwiki-commons-xml/src/main/java/org/xwiki/xml/internal/html/DefaultHTMLCleaner.java+18 −2 modified@@ -267,6 +267,13 @@ private CleanerProperties getDefaultCleanerProperties(HTMLCleanerConfiguration c defaultProperties.setDeserializeEntities(true); + // Omit comments in restricted mode to avoid any potential parser confusion. + // Any part of the filtered HTML that contains unfiltered input is potentially dangerous/a candidate for + // parser confusion. Comments, style and script elements seem to be frequently found ingredients in successful + // attacks against good sanitizers. We're already removing style and script elements, so removing comments + // seems like a good defense against future attacks. + defaultProperties.setOmitComments(isRestricted(configuration)); + return defaultProperties; } @@ -314,8 +321,7 @@ private TrimAttributeCleanerTransformations getDefaultCleanerTransformations(HTM defaultTransformations.addTransformation(tt); } - String restricted = configuration.getParameters().get(HTMLCleanerConfiguration.RESTRICTED); - if ("true".equalsIgnoreCase(restricted)) { + if (isRestricted(configuration)) { tt = new TagTransformation(HTMLConstants.TAG_SCRIPT, HTMLConstants.TAG_PRE, false); defaultTransformations.addTransformation(tt); @@ -336,6 +342,16 @@ private boolean isHTML5(HTMLCleanerConfiguration configuration) return getHTMLVersion(configuration) == 5; } + /** + * @param configuration the configuration to parse + * @return if the parsing should happen in restricted mode + */ + private boolean isRestricted(HTMLCleanerConfiguration configuration) + { + String restricted = configuration.getParameters().get(HTMLCleanerConfiguration.RESTRICTED); + return "true".equalsIgnoreCase(restricted); + } + /** * @param configuration The configuration to parse. * @return The HTML version specified in the configuration.
xwiki-commons-core/xwiki-commons-xml/src/test/java/org/xwiki/xml/internal/html/DefaultHTMLCleanerTest.java+40 −0 modified@@ -33,6 +33,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.w3c.dom.Document; import org.w3c.dom.NodeList; import org.xwiki.component.manager.ComponentManager; @@ -327,6 +329,44 @@ void restrictedAttributesAndTags() throws Exception + "</mi></math>"); } + /** + * Verify comment handling in restricted mode. + */ + @ParameterizedTest + @CsvSource({ + "<p><strong>Hello World</strong></p>,<strong>Hello <!-- a comment --> World</strong>", + "'', <!--My favorite operators are > and <!-->", + // FIXME: Actually, just the comment should be removed but due to erroneous parsing in HTMLCleaner, the whole + // string is treated as a comment. + "'', <!--> <a href=\"#\">no comment</a>", + "'', <!---> <a href=\"#\">no comment</a>" + }) + void restrictedComments(String expected, String actual) + { + Map<String, String> parameters = new HashMap<>(this.cleanerConfiguration.getParameters()); + parameters.put("restricted", "true"); + this.cleanerConfiguration.setParameters(parameters); + + assertHTML(expected, actual); + } + + @ParameterizedTest + @CsvSource({ + "<!--My favorite operators are > and <!-->, <!--My favorite operators are > and <!-->", + "<!-- a comment ==!> not a comment-->, <!-- a comment --!> not a comment", + // FIXME: this is wrongly parsed as a full comment. + "<!-- <a foo=`bar`>not a comment</a>-->, <!--> <a foo=`bar`>not a comment</a>", + "<!--=>-->, <!--->", + // FIXME: according to the HTML specification, this should be a comment. + "'', <! fake comment >", + "<!-- <!== comment -->, <!-- <!-- comment -->", + "<!--My favorite operators are > and <!=-->, <!--My favorite operators are > and <!--->" + }) + void comments(String expected, String actual) + { + assertHTML(expected, actual); + } + /** * Verify that passing a fully-formed XHTML header works fine. */
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-x37v-36wv-6v6hghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-29528ghsaADVISORY
- github.com/xwiki/xwiki-commons/commit/8ff1a9d7e5d7b45b690134a537d53dc05cae04abghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-commons/security/advisories/GHSA-x37v-36wv-6v6hghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XCOMMONS-2568ghsax_refsource_MISCWEB
- jira.xwiki.org/browse/XWIKI-20348ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.