diff --git a/reposilite-backend/src/main/kotlin/com/reposilite/javadocs/JavadocContainerService.kt b/reposilite-backend/src/main/kotlin/com/reposilite/javadocs/JavadocContainerService.kt index 94f7f9523..05143bf2e 100644 --- a/reposilite-backend/src/main/kotlin/com/reposilite/javadocs/JavadocContainerService.kt +++ b/reposilite-backend/src/main/kotlin/com/reposilite/javadocs/JavadocContainerService.kt @@ -8,21 +8,22 @@ import com.reposilite.shared.badRequest import com.reposilite.shared.badRequestError import com.reposilite.shared.errorResponse import com.reposilite.shared.notFound +import com.reposilite.status.FailureFacade import com.reposilite.storage.api.FileType.FILE import com.reposilite.storage.api.Location +import com.reposilite.storage.api.toLocation import com.reposilite.storage.getSimpleName import com.reposilite.token.AccessTokenIdentifier import io.javalin.http.HttpStatus.INTERNAL_SERVER_ERROR -import panda.std.Result -import panda.std.asSuccess import java.io.FileOutputStream import java.io.InputStream import java.io.OutputStream import java.nio.file.Files import java.nio.file.Path -import java.nio.file.Paths import java.util.jar.JarFile import kotlin.io.path.outputStream +import panda.std.Result +import panda.std.asSuccess private const val INDEX_FILE = "index.html" @@ -33,6 +34,7 @@ internal class JavadocContainer( ) internal class JavadocContainerService( + private val failureFacade: FailureFacade, private val mavenFacade: MavenFacade, private val javadocFolder: Path ) { @@ -116,7 +118,6 @@ internal class JavadocContainerService( !jarPath.getSimpleName().contains("javadoc.jar") -> badRequestError("Invalid javadoc jar! Name must contain: 'javadoc.jar'") Files.isDirectory(jarPath) -> badRequestError("JavaDoc jar path has to be a file!") !Files.isDirectory(javadocUnpackPath) -> badRequestError("Destination must be a directory!") - else -> jarPath.toAbsolutePath().toString() .let { JarFile(it) } .use { jarFile -> @@ -124,16 +125,32 @@ internal class JavadocContainerService( return errorResponse(INTERNAL_SERVER_ERROR, "Invalid javadoc.jar given for extraction") } - jarFile.entries().asSequence().forEach { file -> - if (file.isDirectory) { - return@forEach + jarFile + .entries() + .asSequence() + .forEach { file -> + if (file.isDirectory) { + return@forEach + } + + // GHSA-frvj-cfq4-3228: treat archive file name as external path that can be malicious + val processedArchiveFileLocation = file.name.toLocation() + + processedArchiveFileLocation + .toPath() + .map { javadocUnpackPath.resolve(it) } + .peek { + it.parent?.also { parent -> Files.createDirectories(parent) } + jarFile.getInputStream(file).copyToAndClose(it.outputStream()) + } + .onError { + failureFacade.throwException( + "Malicious resource path detected: $processedArchiveFileLocation in $jarPath", + IllegalArgumentException("Malicious resource path detected: $it") + ) + } } - - val path = Paths.get(javadocUnpackPath.toString() + "/" + file.name) - - path.parent?.also { parent -> Files.createDirectories(parent) } - jarFile.getInputStream(file).copyToAndClose(path.outputStream()) - }.asSuccess() + .asSuccess() } .also { Files.deleteIfExists(jarPath) } }