CVE-2023-29528 (Java, published 2023-04-20T18:15Z)
Description: value: XWiki Commons are technical libraries common to several other top level XWiki projects. The "restricted" mode of the HTML cleaner in XWiki, introduced in version 4.2-milestone-1 and massively improved in version 14.6-rc-1, allowed the injection of arbitrary HTML code and thus cross-site scripting via invalid HTML comments. As a consequence, any code relying on this "restricted" mode for security is vulnerable to JavaScript injection ("cross-site scripting"/XSS). When a privileged user with programming rights visits such a comment in XWiki, the malicious JavaScript code is executed in the context of the user session. This allows server-side code execution with programming rights, impacting the confidentiality, integrity and availability of the XWiki instance. This problem has been patched in XWiki 14.10, HTML comments are now removed in restricted mode and a check has been introduced that ensures that comments don't start with `>`. There are no known workarounds apart from upgrading to a version including the fix.

Severity: nan (CVSS v3 base score: 9)
Weakness: CWE-79 \u2014 Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
Repository: https://github.com/xwiki/xwiki-commons
Files changed:
xwiki-commons-core/xwiki-commons-xml/src/main/java/org/xwiki/xml/html/HTMLUtils.java
xwiki-commons-core/xwiki-commons-xml/src/main/java/org/xwiki/xml/internal/html/DefaultHTMLCleaner.java
xwiki-commons-core/xwiki-commons-xml/src/test/java/org/xwiki/xml/internal/html/DefaultHTMLCleanerTest.java
Commit message: XCOMMONS-2568: Improve comment handling in HTMLCleaner (#306)



Vulnerable code:
        String restricted = configuration.getParameters().get(HTMLCleanerConfiguration.RESTRICTED);
        if ("true".equalsIgnoreCase(restricted)) {

Fixed code:
import org.jdom.Comment;

        @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));
        }
        // 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));

        if (isRestricted(configuration)) {
    /**
     * @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);
    }

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
    /**
     * 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);
    }