Apache Archiva privilege escalation
Description
Privilege escalation via stored XSS using the file upload service to upload malicious content. The issue can be exploited only by authenticated users which can create directory name to inject some XSS content and gain some privileges such admin user.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Authenticated stored XSS in Apache Archiva file upload allows privilege escalation via malicious directory names.
Vulnerability
Description
CVE-2023-28158 is a privilege escalation vulnerability in Apache Archiva, the build artifact repository manager. The issue stems from stored cross-site scripting (XSS) in the file upload service. An authenticated attacker can inject malicious content through specially crafted directory names during file upload operations, bypassing insufficient input validation [1].
Exploitation
The attack requires authentication, as only authenticated users can upload files and create directories. By providing a directory name containing HTML or JavaScript payloads (e.g., containing <, >, or & characters), the attacker triggers stored XSS. The patch diffs show that Archiva previously lacked checks for these characters in directory names, and also used escapeJavaScript instead of the more appropriate escapeHtml for certain parameters [2][3].
Impact
Successful exploitation allows the attacker to execute arbitrary JavaScript in the context of the Archiva web interface. This can be leveraged to perform actions on behalf of a higher-privileged user viewing the malicious directory entry, ultimately leading to privilege escalation to admin-level access [1][4].
Mitigation
The vulnerability has been patched in the Apache Archiva codebase. Commit d62e81c7e75f617cf01d2a75952a2c857758f8c4 adds input validation for the <, >, and & characters in directory names and switches from escapeJavaScript to escapeHtml for several parameters [3]. Administrators should update to the patched version as soon as possible. No workaround is documented, and there is no indication that CVE-2023-28158 has been added to the CISA Known Exploited Vulnerabilities catalog.
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.apache.archiva:archivaMaven | >= 2.0.0, < 2.2.10 | 2.2.10 |
Affected products
2- Apache Software Foundation/Apache Archivav5Range: 2.0
Patches
3d62e81c7e75fbetter testing of characters
1 file changed · +19 −10
archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/api/DefaultFileUploadService.java+19 −10 modified@@ -262,6 +262,15 @@ private boolean hasValidChars(String checkString) { if (checkString.contains("/..")) { return false; } + if (checkString.contains("<")) { + return false; + } + if (checkString.contains(">")) { + return false; + } + if (checkString.contains("&")) { + return false; + } return true; } @@ -280,11 +289,11 @@ public Boolean save( String repositoryId, String groupId, String artifactId, Str boolean generatePom ) throws ArchivaRestServiceException { - repositoryId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( repositoryId ) ); - groupId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( groupId ) ); - artifactId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( artifactId ) ); - version = StringEscapeUtils.escapeJavaScript( StringUtils.trim( version ) ); - packaging = StringEscapeUtils.escapeJavaScript( StringUtils.trim( packaging ) ); + repositoryId = StringEscapeUtils.escapeHtml( StringUtils.trim( repositoryId ) ); + groupId = StringEscapeUtils.escapeHtml( StringUtils.trim( groupId ) ); + artifactId = StringEscapeUtils.escapeHtml( StringUtils.trim( artifactId ) ); + version = StringEscapeUtils.escapeHtml( StringUtils.trim( version ) ); + packaging = StringEscapeUtils.escapeHtml( StringUtils.trim( packaging ) ); checkParamChars("repositoryId", repositoryId); checkParamChars("groupId", groupId); @@ -378,11 +387,11 @@ protected void savePomFile( String repositoryId, FileMetadata fileMetadata, Stri ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId ); - repositoryId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( repositoryId ) ); - groupId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( groupId ) ); - artifactId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( artifactId ) ); - version = StringEscapeUtils.escapeJavaScript( StringUtils.trim( version ) ); - packaging = StringEscapeUtils.escapeJavaScript( StringUtils.trim( packaging ) ); + repositoryId = StringEscapeUtils.escapeHtml( StringUtils.trim( repositoryId ) ); + groupId = StringEscapeUtils.escapeHtml( StringUtils.trim( groupId ) ); + artifactId = StringEscapeUtils.escapeHtml( StringUtils.trim( artifactId ) ); + version = StringEscapeUtils.escapeHtml( StringUtils.trim( version ) ); + packaging = StringEscapeUtils.escapeHtml( StringUtils.trim( packaging ) ); ArtifactReference artifactReference = new ArtifactReference(); artifactReference.setArtifactId( artifactId );
e7f7e70992d3fix tomcat:run with last log4j api and multi release jars
3 files changed · +124 −7
archiva-modules/archiva-web/archiva-webapp/pom.xml+109 −0 modified@@ -45,6 +45,7 @@ <archiva.repositorySessionFactory.id>jcr</archiva.repositorySessionFactory.id> <cassandra.host>localhost</cassandra.host> <cassandra.port>9160</cassandra.port> + <tomcat7Version>7.0.76</tomcat7Version> </properties> <dependencies> @@ -852,6 +853,7 @@ <org.apache.sirona.configuration.sirona.properties>${archiva.sirona.configuration}</org.apache.sirona.configuration.sirona.properties> <AsyncLoggerConfig.WaitStrategy>Block</AsyncLoggerConfig.WaitStrategy> <AsyncLogger.WaitStrategy>Block</AsyncLogger.WaitStrategy> + <tomcat.util.scan.DefaultJarScanner.jarsToSkip>log4j-*.jar</tomcat.util.scan.DefaultJarScanner.jarsToSkip> </systemProperties> <additionalClasspathDirs> <additionalClasspathDir>${basedir}/src/test/tomcat</additionalClasspathDir> @@ -868,6 +870,113 @@ <artifactId>mail</artifactId> <version>${javaxMailVersion}</version> </dependency> + <!-- insane but needed because of this https://bz.apache.org/bugzilla/show_bug.cgi?id=60688 --> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-core</artifactId> + <version>${tomcat7Version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-util</artifactId> + <version>${tomcat7Version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-coyote</artifactId> + <version>${tomcat7Version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-api</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jdbc</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-dbcp</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-servlet-api</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jsp-api</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jasper</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-jasper-el</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-el-api</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-catalina</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-tribes</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-catalina-ha</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-annotations-api</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <!-- tomcat i18n too ?? --> + + <!-- not sure we need that --> + <dependency> + <groupId>org.apache.tomcat</groupId> + <artifactId>tomcat-juli</artifactId> + <version>${tomcat7Version}</version> + </dependency> + + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-juli</artifactId> + <version>${tomcat7Version}</version> + </dependency> + <dependency> + <groupId>org.apache.tomcat.embed</groupId> + <artifactId>tomcat-embed-logging-log4j</artifactId> + <version>${tomcat7Version}</version> + </dependency> </dependencies> </plugin>
archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/api/DefaultFileUploadService.java+12 −5 modified@@ -50,6 +50,7 @@ import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.BooleanUtils; +import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; import org.apache.cxf.jaxrs.ext.multipart.Attachment; @@ -279,11 +280,11 @@ public Boolean save( String repositoryId, String groupId, String artifactId, Str boolean generatePom ) throws ArchivaRestServiceException { - repositoryId = StringUtils.trim( repositoryId ); - groupId = StringUtils.trim( groupId ); - artifactId = StringUtils.trim( artifactId ); - version = StringUtils.trim( version ); - packaging = StringUtils.trim( packaging ); + repositoryId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( repositoryId ) ); + groupId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( groupId ) ); + artifactId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( artifactId ) ); + version = StringEscapeUtils.escapeJavaScript( StringUtils.trim( version ) ); + packaging = StringEscapeUtils.escapeJavaScript( StringUtils.trim( packaging ) ); checkParamChars("repositoryId", repositoryId); checkParamChars("groupId", groupId); @@ -377,6 +378,12 @@ protected void savePomFile( String repositoryId, FileMetadata fileMetadata, Stri ManagedRepository repoConfig = managedRepositoryAdmin.getManagedRepository( repositoryId ); + repositoryId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( repositoryId ) ); + groupId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( groupId ) ); + artifactId = StringEscapeUtils.escapeJavaScript( StringUtils.trim( artifactId ) ); + version = StringEscapeUtils.escapeJavaScript( StringUtils.trim( version ) ); + packaging = StringEscapeUtils.escapeJavaScript( StringUtils.trim( packaging ) ); + ArtifactReference artifactReference = new ArtifactReference(); artifactReference.setArtifactId( artifactId ); artifactReference.setGroupId( groupId );
archiva-modules/archiva-web/archiva-web-common/src/test/java/org/apache/archiva/upload/UploadArtifactsTest.java+3 −2 modified@@ -28,7 +28,6 @@ import org.apache.archiva.web.api.FileUploadService; import org.apache.archiva.web.model.FileMetadata; import org.apache.catalina.Context; -import org.apache.catalina.LifecycleException; import org.apache.catalina.deploy.ApplicationParameter; import org.apache.catalina.startup.Tomcat; import org.apache.commons.io.FileUtils; @@ -337,7 +336,9 @@ public void failSaveFileWithBadParams( ) throws IOException, ArchivaRestServiceE meta = service.post( body ); log.debug( "Metadata {}", meta.toString( ) ); try { - service.save("internal", "org", URLEncoder.encode("../../../test", "UTF-8"), URLEncoder.encode("testSave", "UTF-8"), "4", true); + service.save("internal", "org", + URLEncoder.encode("../../../test", "UTF-8"), + URLEncoder.encode("testSave", "UTF-8"), "4", true); fail("Error expected, if the content contains bad characters."); } catch (ClientErrorException e) { assertEquals(422, e.getResponse().getStatus());
ee3ee0a18977[MRM-1793] trailing spaces not trimmed in upload form
1 file changed · +8 −2
archiva-modules/archiva-web/archiva-web-common/src/main/java/org/apache/archiva/web/api/DefaultFileUploadService.java+8 −2 modified@@ -210,10 +210,16 @@ public List<FileMetadata> getSessionFileMetadatas() return fileMetadatas == null ? Collections.<FileMetadata>emptyList() : fileMetadatas; } - public Boolean save( String repositoryId, final String groupId, final String artifactId, String version, - String packaging, final boolean generatePom ) + public Boolean save( String repositoryId, String groupId, String artifactId, String version, + String packaging, boolean generatePom ) throws ArchivaRestServiceException { + repositoryId = StringUtils.trim( repositoryId ); + groupId = StringUtils.trim( groupId ); + artifactId = StringUtils.trim( artifactId ); + version = StringUtils.trim( version ); + packaging = StringUtils.trim( packaging ); + List<FileMetadata> fileMetadatas = getSessionFilesList(); if ( fileMetadatas == null || fileMetadatas.isEmpty() ) {
Vulnerability mechanics
Synthesis attempt was rejected by the grounding validator. Re-run pending.
References
8- github.com/advisories/GHSA-qf34-f43r-gv9pghsaADVISORY
- lists.apache.org/thread/8pm6d5y9cptznm0bdny3n8voovmm0dttghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2023-28158ghsaADVISORY
- www.openwall.com/lists/oss-security/2023/04/18/2ghsaWEB
- github.com/apache/archiva/commit/d62e81c7e75f617cf01d2a75952a2c857758f8c4ghsaWEB
- github.com/apache/archiva/commit/e7f7e70992d361d8b7a3298ddcdf49dda2fdc842ghsaWEB
- github.com/apache/archiva/commit/ee3ee0a18977b67b6997ea8cd023816201059f96ghsaWEB
- github.com/apache/archiva/releases/tag/archiva-2.2.10ghsaWEB
News mentions
0No linked articles in our index yet.