org.xwiki.platform:xwiki-platform-rendering-parser vulnerable to Improper Handling of Exceptional Conditions
Description
XWiki Platform is a generic wiki platform. Starting in version 6.0, users with write rights can insert well-formed content that is not handled well by the parser. As a consequence, some pages becomes unusable, including the user index (if the page containing the faulty content is a user page) and the page index.
Note that on the page, the normal UI is completely missing and it is not possible to open the editor directly to revert the change as the stack overflow is already triggered while getting the title of the document. This means that it is quite difficult to remove this content once inserted.
This has been patched in XWiki 13.10.10, 14.4.6, and 14.9-rc-1. A temporary workaround to avoid Stack Overflow errors is to increase the memory allocated to the stack by using the -Xss JVM parameter (e.g., -Xss32m). This should allow the parser to pass and to fix the faulty content. The consequences for other aspects of the system (e.g., performance) are unknown, and this workaround should be only be used as a temporary solution. The workaround does not prevent the issue occurring again with other content. Consequently, it is strongly advised to upgrade to a version where the issue has been patched.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-rendering-parserMaven | >= 6.0, < 13.10.10 | 13.10.10 |
org.xwiki.platform:xwiki-platform-rendering-parserMaven | >= 14.0, < 14.4.6 | 14.4.6 |
org.xwiki.platform:xwiki-platform-rendering-parserMaven | >= 14.5, < 14.9-rc-1 | 14.9-rc-1 |
Affected products
1- Range: >= 6.0, < 13.10.10
Patches
1e5b82cd98072XWIKI-19838: Improve handling of unexpected parser errors
2 files changed · +81 −44
xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-parser/src/main/java/org/xwiki/rendering/internal/parser/DefaultContentParser.java+9 −1 modified@@ -59,7 +59,15 @@ public class DefaultContentParser implements ContentParser @Override public XDOM parse(String content, Syntax syntax) throws ParseException, MissingParserException { - return getParser(syntax).parse(new StringReader(content == null ? "" : content)); + Parser parser = getParser(syntax); + try { + return parser.parse(new StringReader(content == null ? "" : content)); + } catch (StackOverflowError | Exception e) { + // All exceptions as well as stack overflow errors are captured and wrapped in parse exceptions to make sure + // that they are handled correctly by the callers. Without this, some parsing issues can be badly handled, + // leading to instability issues. + throw new ParseException(String.format("Failed to parse with syntax [%s].", syntax.toIdString()), e); + } } @Override
xwiki-platform-core/xwiki-platform-rendering/xwiki-platform-rendering-parser/src/test/java/org/xwiki/rendering/internal/parser/DefaultContentParserTest.java+72 −43 modified@@ -19,93 +19,122 @@ */ package org.xwiki.rendering.internal.parser; -import static org.hamcrest.CoreMatchers.any; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; -import static org.mockito.hamcrest.MockitoHamcrest.argThat; -import static org.mockito.Mockito.when; - import java.io.Reader; -import java.util.Collections; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; +import org.hamcrest.CoreMatchers; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.xwiki.component.internal.ContextComponentManagerProvider; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.model.reference.DocumentReference; import org.xwiki.model.reference.EntityReferenceSerializer; -import org.xwiki.rendering.block.Block; import org.xwiki.rendering.block.XDOM; import org.xwiki.rendering.listener.MetaData; -import org.xwiki.rendering.parser.ContentParser; import org.xwiki.rendering.parser.MissingParserException; +import org.xwiki.rendering.parser.ParseException; import org.xwiki.rendering.parser.Parser; import org.xwiki.rendering.syntax.Syntax; import org.xwiki.test.annotation.ComponentList; -import org.xwiki.test.mockito.MockitoComponentMockingRule; +import org.xwiki.test.junit5.mockito.ComponentTest; +import org.xwiki.test.junit5.mockito.InjectMockComponents; +import org.xwiki.test.junit5.mockito.MockComponent; +import org.xwiki.test.mockito.MockitoComponentManager; + +import static java.util.Collections.emptyList; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.mockito.hamcrest.MockitoHamcrest.argThat; +import static org.xwiki.rendering.syntax.Syntax.PLAIN_1_0; +import static org.xwiki.rendering.syntax.Syntax.XWIKI_2_1; /** - * Unit tests for {@link org.xwiki.rendering.internal.parser.DefaultContentParser}. + * Unit tests for {@link DefaultContentParser}. * * @version $Id$ * @since 6.0M2 */ +@ComponentTest @ComponentList(ContextComponentManagerProvider.class) -public class DefaultContentParserTest +class DefaultContentParserTest { - @Rule - public final MockitoComponentMockingRule<ContentParser> mocker = - new MockitoComponentMockingRule<>(DefaultContentParser.class); - - @Rule - public ExpectedException thrown = ExpectedException.none(); - private static final DocumentReference DOCUMENT_REFERENCE = new DocumentReference("wiki", "space", "page"); + private static final String SOURCE = "wiki:space.page"; - @Before - public void configure() throws Exception - { - Parser parser = mocker.registerMockComponent(Parser.class, Syntax.PLAIN_1_0.toIdString()); - when(parser.parse(argThat(any(Reader.class)))).thenReturn(new XDOM(Collections.<Block>emptyList())); + @InjectMockComponents + private DefaultContentParser defaultContentParser; + + @MockComponent + private EntityReferenceSerializer<String> serializer; - EntityReferenceSerializer<String> serializer = mocker.getInstance(EntityReferenceSerializer.TYPE_STRING); - when(serializer.serialize(DOCUMENT_REFERENCE)).thenReturn(SOURCE); + private Parser plain10parser; + + @BeforeEach + void setUp(MockitoComponentManager componentManager) throws Exception + { + this.plain10parser = componentManager.registerMockComponent(Parser.class, PLAIN_1_0.toIdString()); + when(this.plain10parser.parse(argThat(CoreMatchers.any(Reader.class)))).thenReturn(new XDOM(emptyList())); + when(this.serializer.serialize(DOCUMENT_REFERENCE)).thenReturn(SOURCE); } @Test - public void parseHasNoMetadataSource() throws Exception + void parseHasNoMetadataSource() throws Exception { - XDOM xdom = mocker.getComponentUnderTest().parse("", Syntax.PLAIN_1_0); + XDOM xdom = this.defaultContentParser.parse("", PLAIN_1_0); assertThat(xdom.getMetaData().getMetaData(MetaData.SOURCE), nullValue()); } @Test - public void parseIsAddingMetadataSource() throws Exception + void parseIsAddingMetadataSource() throws Exception { - XDOM xdom = mocker.getComponentUnderTest().parse("", Syntax.PLAIN_1_0, DOCUMENT_REFERENCE); + XDOM xdom = this.defaultContentParser.parse("", PLAIN_1_0, DOCUMENT_REFERENCE); assertThat(xdom.getMetaData().getMetaData(MetaData.SOURCE), equalTo(SOURCE)); } @Test - public void parseWhenNoParser() throws Exception + void parseWhenNoParser() + { + MissingParserException missingParserException = assertThrows(MissingParserException.class, + () -> this.defaultContentParser.parse("", XWIKI_2_1, DOCUMENT_REFERENCE)); + assertEquals(ComponentLookupException.class, missingParserException.getCause().getClass()); + assertEquals("Failed to find a parser for syntax [XWiki 2.1]", missingParserException.getMessage()); + } + + @Test + void parseWhenNoParserFail() throws Exception + { + when(this.plain10parser.parse(any())).thenThrow(StackOverflowError.class); + + ParseException parseErrorException = + assertThrows(ParseException.class, () -> this.defaultContentParser.parse("content", PLAIN_1_0)); + + assertEquals(StackOverflowError.class, parseErrorException.getCause().getClass()); + assertEquals("Failed to parse with syntax [plain/1.0].", parseErrorException.getMessage()); + } + + @Test + void parseWhenNoParserFailWithSource() throws Exception { - thrown.expect(MissingParserException.class); - thrown.expectMessage("Failed to find a parser for syntax [XWiki 2.1]"); - thrown.expectCause(any(ComponentLookupException.class)); - mocker.getComponentUnderTest().parse("", Syntax.XWIKI_2_1, DOCUMENT_REFERENCE); + when(this.plain10parser.parse(any())).thenThrow(StackOverflowError.class); + + ParseException parseErrorException = + assertThrows(ParseException.class, () -> this.defaultContentParser.parse("content", PLAIN_1_0, null)); + + assertEquals(StackOverflowError.class, parseErrorException.getCause().getClass()); + assertEquals("Failed to parse with syntax [plain/1.0].", parseErrorException.getMessage()); } @Test - public void parseWhenNullSource() throws Exception + void parseWhenNullSource() throws Exception { - XDOM xdom = mocker.getComponentUnderTest().parse(null, Syntax.PLAIN_1_0); + XDOM xdom = this.defaultContentParser.parse(null, Syntax.PLAIN_1_0); assertEquals(0, xdom.getChildren().size()); } }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5- github.com/advisories/GHSA-52vf-hvv3-98h7ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-26479ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/e5b82cd98072464196a468b8f7fe6396dce142a7ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-52vf-hvv3-98h7ghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-19838ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.