org.xwiki.platform:xwiki-platform-logging-ui Injection vulnerability
Description
XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. In affected versions of org.xwiki.platform:xwiki-platform-logging-ui it is possible to trick a user with programming rights into visiting a constructed url where e.g., by embedding an image with this URL in a document that is viewed by a user with programming rights which will evaluate an expression in the constructed url and execute it. This issue has been addressed in versions 13.10.11, 14.4.7, and 14.10. Users are advised to upgrade. There are no known workarounds for this vulnerability.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-logging-uiMaven | >= 4.2-milestone-3, < 13.10.11 | 13.10.11 |
org.xwiki.platform:xwiki-platform-logging-uiMaven | >= 14.0-rc-1, < 14.4.7 | 14.4.7 |
org.xwiki.platform:xwiki-platform-logging-uiMaven | >= 14.5, < 14.10 | 14.10 |
Affected products
1- Range: >= 4.2-milestone-3, < 13.10.11
Patches
149fdfd633ddfXWIKI-20291: Improved translations of logging administration
8 files changed · +409 −15
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-script/pom.xml+22 −0 modified@@ -62,4 +62,26 @@ <scope>test</scope> </dependency> </dependencies> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <executions> + <execution> + <id>test-jar</id> + <goals> + <goal>test-jar</goal> + </goals> + <configuration> + <includes> + <include>**/LoggingScriptServiceComponentList.class</include> + <include>**/NullLoggerManager.class</include> + </includes> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> </project>
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-script/src/test/java/org/xwiki/logging/LoggingScriptServiceComponentList.java+53 −0 added@@ -0,0 +1,53 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.logging; + +import java.lang.annotation.Documented; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import org.xwiki.logging.script.LoggingScriptService; +import org.xwiki.test.annotation.ComponentList; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * Component list for {@link LoggingScriptService}. + * + * @version $Id$ + * @since 13.10.11 + * @since 14.4.7 + * @since 14.10RC1 + */ +@Documented +@Retention(RUNTIME) +@Target({ TYPE, METHOD, ANNOTATION_TYPE }) +@ComponentList({ + LoggingScriptService.class, + NullLoggerManager.class +}) +@Inherited +public @interface LoggingScriptServiceComponentList +{ +}
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-script/src/test/java/org/xwiki/logging/NullLoggerManager.java+66 −0 added@@ -0,0 +1,66 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.logging; + +import java.util.Collection; + +import org.slf4j.Logger; +import org.xwiki.observation.EventListener; + +/** + * Null logger manager, to be overridden if need be. + * + * @version $Id$ + * @since 13.10.11 + * @since 14.4.7 + * @since 14.10RC1 + */ +public class NullLoggerManager implements LoggerManager +{ + @Override + public void pushLogListener(EventListener listener) + { + + } + + @Override + public EventListener popLogListener() + { + return null; + } + + @Override + public void setLoggerLevel(String loggerName, LogLevel level) + { + + } + + @Override + public LogLevel getLoggerLevel(String loggerName) + { + return null; + } + + @Override + public Collection<Logger> getLoggers() + { + return null; + } +}
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-ui/pom.xml+31 −0 modified@@ -80,5 +80,36 @@ <version>${project.version}</version> <scope>runtime</scope> </dependency> + <!-- Test dependencies. --> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-test-page</artifactId> + <version>${project.version}</version> + <scope>test</scope> + </dependency> + <!-- Provides the component list for RenderingScriptService. --> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-rendering-xwiki</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <!-- Provides the component list for the LiveData macro. --> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-livedata-macro</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <!-- Required for LoggingScriptService. --> + <dependency> + <groupId>org.xwiki.platform</groupId> + <artifactId>xwiki-platform-logging-script</artifactId> + <version>${project.version}</version> + <type>test-jar</type> + <scope>test</scope> + </dependency> </dependencies> </project>
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-ui/src/main/resources/XWiki/LoggingAdmin.xml+17 −8 modified@@ -44,20 +44,28 @@ ## ## Setting the logger level if button has been pressed ## ## -#if ($request.loggeraction_set && $request.logger_name && $xwiki.hasAccessLevel('programming')) +#set ($loggerName = $request.logger_name) +#set ($loggerNameEscaped = $services.rendering.escape($escapetool.java($loggerName), 'xwiki/2.1')) +#set ($loggerLevel = $request.logger_level) +#set ($loggerLevelEscaped = $services.rendering.escape($escapetool.java($loggerLevel), 'xwiki/2.1')) +#if ($request.loggeraction_set && $loggerName && $xwiki.hasAccessLevel('programming')) #set($logger_list = $logging.getLevels()) - #if ($!logger_list.containsKey($request.logger_name)) + #if ($!logger_list.containsKey($loggerName)) #if ($request.logger_level == '') - {{success}}Logger ${request.logger_name} level has been unset.{{/success}} - #set($void = $logging.setLevel($request.logger_name, $null)) + {{success}} + {{translation key='logging.admin.unsetLevel.success' parameters="~"${loggerNameEscaped}~""/}} + {{/success}} + #set($void = $logging.setLevel($loggerName, $null)) #else - {{success}}Logger ${request.logger_name} level has been set to ${request.logger_level}.{{/success}} - #set($void = $logging.setLevel($request.logger_name, $request.logger_level)) + {{success}} + {{translation key='logging.admin.setLevel.success' + parameters="~"${loggerNameEscaped}~",~"${loggerLevelEscaped}~""/}} + {{/success}} + #set($void = $logging.setLevel($loggerName, $request.logger_level)) #end #else - {{error}}Failed to set log level: the logger "$request.logger_name" doesn't exist.{{/error}} + {{error}}{{translation key='logging.admin.setLevel.error' parameters="~"${loggerNameEscaped}~""/}}{{/error}} #end - #end ## ## Live Data @@ -77,6 +85,7 @@ 'filterable': false })) #end + {{liveData id="logging" properties="$stringtool.join($properties, ',')"
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-ui/src/main/resources/XWiki/Logging/Code/Translations.xml+79 −0 added@@ -0,0 +1,79 @@ +<?xml version="1.1" encoding="UTF-8"?> + +<!-- + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. +--> + +<xwikidoc version="1.5" reference="XWiki.Logging.Code.Translations" locale=""> + <web>XWiki.Logging.Code</web> + <name>Translations</name> + <language/> + <defaultLanguage>en</defaultLanguage> + <translation>0</translation> + <creator>xwiki:XWiki.Admin</creator> + <parent>WebHome</parent> + <author>xwiki:XWiki.Admin</author> + <contentAuthor>xwiki:XWiki.Admin</contentAuthor> + <version>1.1</version> + <title>Translations</title> + <comment/> + <minorEdit>false</minorEdit> + <syntaxId>plain/1.0</syntaxId> + <hidden>true</hidden> + <content>logging.admin.unsetLevel.success=Logger "{0}" level has been unset. +logging.admin.setLevel.success=Logger "{0}" level has been set to "{1}". +logging.admin.setLevel.error=Failed to set log level: the logger "{0}" doesn't exist.</content> + <object> + <name>XWiki.Logging.Code.Translations</name> + <number>0</number> + <className>XWiki.TranslationDocumentClass</className> + <guid>fc29bfac-011a-4573-80ba-3f5713f1e847</guid> + <class> + <name>XWiki.TranslationDocumentClass</name> + <customClass/> + <customMapping/> + <defaultViewSheet/> + <defaultEditSheet/> + <defaultWeb/> + <nameField/> + <validationScript/> + <scope> + <cache>0</cache> + <disabled>0</disabled> + <displayType>select</displayType> + <freeText>forbidden</freeText> + <largeStorage>0</largeStorage> + <multiSelect>0</multiSelect> + <name>scope</name> + <number>1</number> + <prettyName>Scope</prettyName> + <relationalStorage>0</relationalStorage> + <separator> </separator> + <separators>|, </separators> + <size>1</size> + <unmodifiable>0</unmodifiable> + <values>GLOBAL|WIKI|USER|ON_DEMAND</values> + <classType>com.xpn.xwiki.objects.classes.StaticListClass</classType> + </scope> + </class> + <property> + <scope>WIKI</scope> + </property> + </object> +</xwikidoc>
xwiki-platform-core/xwiki-platform-logging/xwiki-platform-logging-ui/src/test/java/org/xwiki/logging/LoggingAdminPageTest.java+138 −0 added@@ -0,0 +1,138 @@ +/* + * See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.xwiki.logging; + +import java.util.HashMap; + +import org.jsoup.nodes.Document; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.xwiki.icon.IconManager; +import org.xwiki.livedata.internal.macro.LiveDataMacroComponentList; +import org.xwiki.localization.macro.internal.TranslationMacro; +import org.xwiki.model.reference.DocumentReference; +import org.xwiki.properties.internal.converter.EnumConverter; +import org.xwiki.rendering.RenderingScriptServiceComponentList; +import org.xwiki.rendering.internal.configuration.DefaultExtendedRenderingConfiguration; +import org.xwiki.rendering.internal.configuration.RenderingConfigClassDocumentConfigurationSource; +import org.xwiki.rendering.internal.macro.message.ErrorMessageMacro; +import org.xwiki.rendering.internal.macro.message.SuccessMessageMacro; +import org.xwiki.security.authorization.ContextualAuthorizationManager; +import org.xwiki.test.annotation.ComponentList; +import org.xwiki.test.page.HTML50ComponentList; +import org.xwiki.test.page.PageTest; +import org.xwiki.test.page.XWikiSyntax21ComponentList; + +import com.xpn.xwiki.plugin.skinx.SkinExtensionPluginApi; + +import static java.util.Arrays.asList; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Test of {@code XWiki.LoggingAdmin}. + * + * @version $Id$ + * @since 13.10.11 + * @since 14.4.7 + * @since 14.10RC1 + */ +@XWikiSyntax21ComponentList +@HTML50ComponentList +@RenderingScriptServiceComponentList +@LiveDataMacroComponentList +@LoggingScriptServiceComponentList +@ComponentList({ + TranslationMacro.class, + DefaultExtendedRenderingConfiguration.class, + RenderingConfigClassDocumentConfigurationSource.class, + ErrorMessageMacro.class, + SuccessMessageMacro.class, + EnumConverter.class +}) +class LoggingAdminPageTest extends PageTest +{ + private LoggerManager loggerManager; + + @BeforeEach + void setUp() throws Exception + { + // Spy the jsfx plugin used during the macro rendering to return a mock of its API when required. + when(this.oldcore.getSpyXWiki().getPluginApi("jsfx", this.context)) + .thenReturn(mock(SkinExtensionPluginApi.class)); + // Return minimal icons metadata since this is not what we want to test here. + IconManager iconManager = this.componentManager.registerMockComponent(IconManager.class); + doReturn(new HashMap<>()).when(iconManager).getMetaData(anyString()); + // Setting all rights as allowed by default. + when(this.xwiki.getRightService().hasAccessLevel(any(), any(), anyString(), eq(this.context))) + .thenReturn(true); + when(this.componentManager.<ContextualAuthorizationManager>getInstance(ContextualAuthorizationManager.class) + .hasAccess(any())).thenReturn(true); + // Register a mocked LoggerManager as we want to control the logger level. + this.loggerManager = this.componentManager.registerMockComponent(LoggerManager.class); + Logger loggerA = mock(Logger.class); + when(loggerA.getName()).thenReturn("loggerA"); + when(this.loggerManager.getLoggers()).thenReturn(asList(loggerA)); + } + + @Test + void unknownLogger() throws Exception + { + this.request.put("loggeraction_set", "1"); + this.request.put("logger_name", "{{cache}}{{groovy}}new File(\"/tmp/exploit.txt\").withWriter { out -> " + + "out.println(\"created from notification filter preferences!\"); " + + "}{{/groovy}}{{/cache}}<strong>bold</strong>\"'"); + this.request.put("logger_level", "TRACE"); + Document document = renderHTMLPage(new DocumentReference("xwiki", "XWiki", "LoggingAdmin")); + assertEquals("logging.admin.setLevel.error [{{cache}}{{groovy}}new File(\"/tmp/exploit.txt\")" + + ".withWriter { out -> out.println(\"created from notification filter preferences!\"); }{{/groovy}}" + + "{{/cache}}<strong>bold</strong>\"']", document.select(".box.errormessage").text()); + verify(this.loggerManager, never()).setLoggerLevel(any(), any()); + } + + @Test + void unsetLogger() throws Exception + { + this.request.put("loggeraction_set", "1"); + this.request.put("logger_name", "loggerA"); + this.request.put("logger_level", ""); + Document document = renderHTMLPage(new DocumentReference("xwiki", "XWiki", "LoggingAdmin")); + assertEquals("logging.admin.unsetLevel.success [loggerA]", document.select(".box.successmessage").text()); + verify(this.loggerManager).setLoggerLevel("loggerA", null); + } + + @Test + void setLogger() throws Exception + { + this.request.put("loggeraction_set", "1"); + this.request.put("logger_name", "loggerA"); + this.request.put("logger_level", "TRACE"); + Document document = renderHTMLPage(new DocumentReference("xwiki", "XWiki", "LoggingAdmin")); + assertEquals("logging.admin.setLevel.success [loggerA, TRACE]", document.select(".box.successmessage").text()); + verify(this.loggerManager).setLoggerLevel("loggerA", LogLevel.TRACE); + } +}
xwiki-platform-core/xwiki-platform-test/xwiki-platform-test-page/src/main/java/org/xwiki/test/page/LocalizationSetup.java+3 −7 modified@@ -127,13 +127,9 @@ private static String renderString(String translationKey, Object[] parameters) private static Object[] getVarArgs(InvocationOnMock invocationOnMockRender, int i) { Object[] parameters; - if (invocationOnMockRender.getArguments().length > i) { - Object argument = invocationOnMockRender.getArgument(i); - if (argument instanceof String) { - parameters = new Object[] { argument }; - } else { - parameters = (Object[]) argument; - } + Object[] arguments = invocationOnMockRender.getArguments(); + if (arguments.length > i) { + parameters = Arrays.copyOfRange(arguments, i, arguments.length); } else { parameters = new Object[] {}; }
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-4655-wh7v-3vmgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2023-29213ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/49fdfd633ddfa346c522d2fe71754dc72c9496caghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-4655-wh7v-3vmgghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-20291ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.