
Reproducible study of CVE-2024-36401: unauthenticated RCE in GeoServer via JXPath eval injection. Includes technical report, working exploit/verifier, and Docker environment demonstrating the flaw on vulnerable vs. patched instances.
A complete, reproducible study of CVE-2024-36401, an unauthenticated remote code
execution flaw in GeoServer — the most widely deployed
open-source server for geospatial data. The bug is an eval injection: through the
parameters of the OGC standards, GeoServer hands attacker-controlled property names
to GeoTools, where Apache Commons JXPath evaluates them as XPath expressions and,
by design, can call arbitrary Java methods via reflection. An unauthenticated request
such as exec(java.lang.Runtime.getRuntime(),'id') therefore runs commands on the host.
This repo contains the technical report, a working exploit/verifier, and a one-command Docker environment that demonstrates the RCE on a vulnerable instance and shows the same exploit failing on the patched one.
Educational project. Built for a university course (Data Privacy and Security, LUISS DASMA). Everything runs only against local, isolated containers — see .
| Field | Value |
|---|---|
| CVE (GeoServer) | CVE-2024-36401 |
| Root cause (GeoTools) | CVE-2024-36404 |
| Type | Unauthenticated Remote Code Execution |
| CWE | CWE-95, Eval Injection |
| CVSS v3.1 | 9.8 Critical (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H) |
| Affected | GeoServer < 2.25.2 / GeoTools < 31.2 (and earlier branches) |
| CISA KEV | Yes (15 July 2024) |
| Versions studied | Vulnerable 2.25.1, patched 2.25.2 |
.
├── report/
│ ├── report.pdf # the full technical report (read this first)
│ ├── report.md # report source (Pandoc/XeLaTeX)
│ └── images/ # figures and screenshots
├── docker/
│ ├── vulnerable/Dockerfile # GeoServer 2.25.1 (vulnerable)
│ └── patched/Dockerfile # GeoServer 2.25.2 (fixed)
├── docker-compose.yml # vuln on :8080, patched on :8081
├── exploit/
│ ├── exploit.py # exploit + vuln/patched verifier (stdlib only)
│ ├── exploit.sh # curl-based PoC (GET + POST variants)
│ ├── payloads.md # payload catalogue per OGC endpoint
│ └── output/ # captured proof logs and transcripts
└── run-reproduction.sh # one command: build + exploit both + collect proofs
Requirements: Docker Desktop running, python3, curl.
# Build both containers, run the exploit against each, and collect the proofs
chmod +x run-reproduction.sh
./run-reproduction.sh
Or step by step:
docker compose up -d --build # vuln on :8080, patched on :8081
# Vulnerable (expected: VULNERABLE, ~8s delay)
python3 exploit/exploit.py -t http://localhost:8080/geoserver --label vuln -o exploit/output
# Patched (expected: PATCHED, immediate rejection)
python3 exploit/exploit.py -t http://localhost:8081/geoserver --label patched -o exploit/output
docker compose down # when finished
Two independent probes make the result unambiguous:
java.lang.Thread.sleep(8000) blocks the thread evaluating the
XPath, so the HTTP response is delayed by ~8 s — measurable from the client, no container
access needed. It is the same canary used by the official fix tests.exec(java.lang.Runtime.getRuntime(),'touch /tmp/<marker>')
creates a file inside the container, verifiable with docker exec.On the vulnerable instance, sending the payload by hand returns a ClassCastException on
ProcessImpl — the JVM ran Runtime.exec and then failed to use the resulting Process
object as an attribute. That exception is the proof of execution:

GeoTools commit e53e5170 (in GeoServer
2.25.2, 2.24.4, 2.23.6, 2.22.6) applies defence in depth on both halves of the bug:
JXPathUtils.newSafeContext(...) helper installs an empty FunctionLibrary,
so JXPath can no longer resolve exec/Thread.sleep as functions — the string stays a
plain property name.FeaturePropertyAccessorFactory now also checks SimpleFeatureType, so simple
features no longer reach the vulnerable accessor.On the patched instance the same payload returns No such attribute: ... and nothing runs.
Full details — affected code with file/line references, exploitation, mitigation diff, and
the side-by-side reproduction — are in report/report.pdf.
This CVE is public, has been patched for over 18 months, sits in the CISA Known Exploited
Vulnerabilities catalogue, and has public PoCs (Vulhub, Nuclei, Metasploit). The code here
targets only localhost and the isolated study containers in this repository. Do not use
it against systems you do not own or are not explicitly authorised to test.
MIT © 2026 Daniele Giovanardi
Daniele Giovanardi — Data Science and Management (DASMA), LUISS Guido Carli. Coursework for Data Privacy and Security.