From 96d06b0ab848d5f004b3d56bdd498ce057425c0d Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sun, 4 Oct 2026 17:31:57 +0200 Subject: [PATCH] =?utf8?q?=F0=9F=94=92=EF=B8=8F=20Fix=20XXE=20vulnerabilit?= =?utf8?q?y=20and=20add=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit While the parser in its configuration was vulnerable to XXE, you could only ever manipulate XML files that you inserted, and it was never possible to force other Sone instances to re-export any data from your modified XML files. --- build.gradle | 2 +- .../net/pterodactylus/sone/core/SoneParserTest.kt | 51 ++++++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 938d645..066377c 100644 --- a/build.gradle +++ b/build.gradle @@ -47,7 +47,7 @@ dependencies { implementation group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib-jdk8' implementation group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-core', version: '1.3.0-RC' - implementation group: 'net.pterodactylus', name: 'utils', version: '0.13.1' + implementation group: 'net.pterodactylus', name: 'utils', version: '0.13.2' implementation group: 'com.google.inject', name: 'guice', version: '7.0.0' implementation group: 'com.google.guava', name: 'guava', version: '33.3.1-jre' implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.0' diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt index 38419a2..5af592a 100644 --- a/src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt @@ -2,6 +2,7 @@ package net.pterodactylus.sone.core import com.codahale.metrics.* import com.google.common.base.Optional.* +import com.sun.net.httpserver.HttpServer import freenet.crypt.* import freenet.keys.InsertableClientSSK.* import net.pterodactylus.sone.data.* @@ -14,8 +15,12 @@ import org.hamcrest.MatcherAssert.* import org.hamcrest.Matchers.* import org.mockito.Mockito.* import java.lang.System.* +import java.net.InetAddress +import java.net.InetSocketAddress import java.util.concurrent.TimeUnit.* import kotlin.test.* +import org.junit.Rule +import org.junit.rules.TemporaryFolder /** * Unit test for [SoneParser]. @@ -415,4 +420,50 @@ class SoneParserTest { assertThat(histogram.count, equalTo(1L)) } + @Test + fun `custom entities will not cause files to be included`() { + val fileToRead = temporaryFolder.newFile() + fileToRead.writeText("secret") + val maliciousEntityXml = """ +]> + + 0 + + + xxe: &xxe; + + +""" + assertThat(soneParser.parseSone(sone, maliciousEntityXml.byteInputStream())!!.profile.firstName, equalTo("xxe: ")) + } + + @Test + fun `custom entities will not cause URLs to be included`() { + val httpServer = HttpServer.create(InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0) + httpServer.createContext("/test") { exchange -> + exchange.sendResponseHeaders(200, 6) + exchange.responseBody.write("secret".encodeToByteArray()) + } + httpServer.start() + try { + val maliciousEntityXml = """ +]> + + 0 + + + xxe: &xxe; + + +""" + assertThat(soneParser.parseSone(sone, maliciousEntityXml.byteInputStream())!!.profile.firstName, equalTo("xxe: ")) + } finally { + httpServer.stop(0) + } + } + + @Rule + @JvmField + val temporaryFolder: TemporaryFolder = TemporaryFolder() + } -- 2.7.4