Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2025-66249-POC — A POC for Apache Livy Path Traversal Whitelist Bypass Vulnerability | Kitploit
Tools/GitHubGitHub/sid6224/cve-2025-66249-poc
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHubsid6224/cve-2025-66249-poc

CVE-2025-66249-POC

A POC for Apache Livy Path Traversal Whitelist Bypass Vulnerability

View Repository
26 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2025-66249 — Apache Livy Path Traversal Whitelist Bypass

CVE Livy Severity CWE Type License Platform Language

For educational and security research purposes only. Do not use against systems you do not own or have explicit written permission to test. → Full Disclaimer


Overview

FieldDetail
CVE IDCVE-2025-66249
SeverityImportant (CVSS N/A — NVD assessment pending as of 2026-03-15)
AffectedApache Livy 0.3.0-incubating through 0.8.0-incubating — only when livy.file.local-dir-whitelist is set to a non-default value
Fixed inApache Livy 0.9.0-incubating
CWECWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Disclosed2026-03-12 (OSS-Sec) / 2026-03-13 (NVD)
ReporterHiroki Egawa (finder)

Vulnerability Description

An authenticated user with access to Livy's REST or JDBC interface can submit a Spark session or batch job with a crafted file-path configuration value that escapes the permitted directory whitelist.

Root cause — Path traversal bypass in whitelist check (Session.scala)

When livy.file.local-dir-whitelist is configured, Livy 0.8.0 validates submitted paths by calling Java's String.startsWith() on the raw, un-normalised path. This check can be bypassed using ../ traversal sequences:

/opt/safe-data/../sensitive/secret.txt

The raw string starts with /opt/safe-data, so the check passes — but the path resolves to /opt/sensitive/secret.txt, which is entirely outside the whitelisted directory.

Trigger condition: The vulnerability can only be exploited when livy.file.local-dir-whitelist is set to a non-default (non-empty) value. If the whitelist is empty (the default), path validation is skipped entirely and the issue is not exercised.

Impact: An attacker who submits a session via the Livy REST API can reference arbitrary local files on the Livy server host. In a shared analytics cluster this translates to potential exposure of credentials, keys, configuration files, or any data readable by the Livy process user.


Affected Source Files

File — Session.scala

Vulnerable (v0.8.0): https://github.com/apache/incubator-livy/blob/v0.8.0-incubating/server/src/main/scala/org/apache/livy/sessions/Session.scala

Fixed (v0.9.0): https://github.com/apache/incubator-livy/blob/v0.9.0-incubating/server/src/main/scala/org/apache/livy/sessions/Session.scala


Source Code — Clone Commands

Both versions were cloned directly from the official Apache Livy GitHub repository using the following exact commands:

Repository: https://github.com/apache/incubator-livy

# Vulnerable version — cloned into ./livy-0.8.0/
git clone --depth=1 --branch v0.8.0-incubating \
    https://github.com/apache/incubator-livy \
    livy-0.8.0

# Fixed version — cloned into ./livy-0.9.0/
git clone --depth=1 --branch v0.9.0-incubating \
    https://github.com/apache/incubator-livy \
    livy-0.9.0
VersionTagResolved commitLocal path
0.8.0-incubatingv0.8.0-incubating78b512658e4baf1183f2b352203ada1928d8111a./livy-0.8.0/
0.9.0-incubatingv0.9.0-incubating7215f209b25b96488189567807eaded00953a492./livy-0.9.0/

Exact Code Diffs

Fix — Session.scala: Paths.get().normalize() before whitelist check

 import java.io.InputStream
 import java.net.{URI, URISyntaxException}
+import java.nio.file.Paths
 import java.security.PrivilegedExceptionAction
+import java.util.concurrent.{Executors, LinkedBlockingQueue, ThreadFactory, ThreadPoolExecutor, TimeUnit}
 import java.util.UUID

 ...

     if (resolved.getScheme() == "file") {
       // Make sure the location is whitelisted before allowing local files to be added.
-      require(livyConf.localFsWhitelist.find(resolved.getPath().startsWith).isDefined,
+      require(livyConf.localFsWhitelist.find(
+        Paths.get(resolved.getPath()).normalize.startsWith).isDefined,
         s"Local path ${uri.getPath()} cannot be added to user sessions.")
     }

Impact in v0.8.0: The raw string startsWith check can be bypassed with a path traversal payload.

Example: if livy.file.local-dir-whitelist = /opt/safe-data

/opt/safe-data/../sensitive/secret.txt
  • v0.8.0: "/opt/safe-data/../sensitive/secret.txt".startsWith("/opt/safe-data") → true (bypassed)
  • v0.9.0: Paths.get("/opt/safe-data/../sensitive/secret.txt").normalize → /opt/sensitive/secret.txt /opt/sensitive/secret.txt.startsWith(/opt/safe-data) → false (blocked)

Diffs were produced by cloning both tags locally (see above) and running:

diff -u \
    livy-0.8.0/server/src/main/scala/org/apache/livy/sessions/Session.scala \
    livy-0.9.0/server/src/main/scala/org/apache/livy/sessions/Session.scala

Attack Vector Summary

Attacker (authenticated REST/JDBC user)
    │
    ▼
POST /sessions
{
  "conf": {
    "spark.jars": "file:///opt/safe-data/../sensitive/secret.txt"
    ← path starts with whitelisted prefix — String.startsWith() passes
    ← but resolves OUTSIDE the directory via ../ traversal
  }
}
    │
    ▼
Livy 0.8.0 — whitelist check bypassed (raw startsWith, no normalisation)
    │
    ▼
Spark reads the file and distributes it to executors
    │
    ▼
Attacker retrieves file contents via job output / logs

Test Environment

All steps in this PoC were executed and validated on the following system:

ComponentDetail
Host OSUbuntu 24.04.4 LTS (Noble Numbat)
Kernel6.17.0-14-generic x86_64
Architecturex86_64
Total Memory15 GiB
Docker Engine28.2.2
Host JDKOpenJDK 17.0.18 (used by host only — containers use eclipse-temurin:11-jdk-focal)
Container base imageeclipse-temurin:11-jdk-focal (JDK 11, Ubuntu Focal)
Spark version (both images)3.1.3 with Hadoop 3.2
Livy version — vulnerable image0.8.0-incubating
Livy version — fixed image0.9.0-incubating

Directory Structure

CVE-2025-66249-POC/
├── docker/
│   ├── fixed/
│   │   ├── Dockerfile
│   │   ├── livy.conf
│   │   └── start.sh
│   └── vulnerable/
│       ├── Dockerfile
│       ├── livy.conf
│       └── start.sh
├── test/
│   └── validate.sh
├── .gitignore
├── LICENSE
└── README.md

Proof of Concept

Overview

docker/vulnerable/   →  image: cve-2025-66249-vulnerable   (Livy 0.8.0 + Spark 3.1.3)
docker/fixed/        →  image: cve-2025-66249-fixed        (Livy 0.9.0 + Spark 3.1.3)
test/validate.sh     →  single script, run unchanged against both environments

Full end-to-end sequence — follow Steps 1 through 4 in order:

Step 1: Build vulnerable image  →  start container  →  verify Livy is up
Step 2: Run validate.sh         →  confirm VULNERABLE (attack HTTP 201)   →  stop container
Step 3: Build fixed image       →  start container  →  verify Livy is up
Step 4: Run validate.sh         →  confirm FIXED    (attack HTTP 400)     →  stop container
Download Tool