FlawOpen

flawopen.com/AI Security/langroid-neo4j-cypher-injection-cve-2026-55615

● CVE-2026-55615 · CVSS v4 9.2[1] · Критический
Исследования · FlawOpen

Langroid CVE-2026-55615: инъекция prompt-to-Cypher

Langroid передавал Cypher от модели в Neo4j без проверки. Обновитесь до 0.65.5; права базы остаются границей безопасности.[1], [2], [4]

Вектор CVSSCVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N[1]
💡 Простыми словами (ELI5)

Библиотекарь получает обычный вопрос и напрямую отдаёт полученные инструкции по базе данных сотруднику с широкими полномочиями. Даже если враждебная записка изменила вопрос, сотрудник исполняет инструкции. CVE-2026-55615 позволяла недоверенному содержимому влиять на Cypher, который Langroid отправлял в Neo4j.[1]

Ключевые понятия и термины

Cypher
Язык запросов Neo4j для чтения и изменения графовых данных. Дополнительные процедуры зависят от настроек сервера и прав учётной записи.[1]
Neo4jChatAgent
Агент Langroid преобразует задачу на обычном языке в Cypher и отправляет запрос в Neo4j через инструменты чтения или записи.[1], [3]
Prompt injection
Недоверенный ввод меняет поведение модели. Запросы модели нужно считать недоверенным вводом.[1]
Least-privilege database role
Учётная запись базы данных с доступом только к нужным данным и операциям. Она важна даже при проверке запросов в приложении.[1], [5]
Валидатор запросов Cypher
Валидатор Langroid 0.65.5 проверяет ключевые слова и шаблоны. Документация предупреждает, что такие проверки можно обойти; это эшелонированная защита, а не граница авторизации. Доступ должны ограничивать права ролей Neo4j.[6], [3]

Связи со стандартами

  • Ссылка CWE для слабого места, описанного в этом руководстве: CWE-74

Пошаговый сценарий атаки

Шаг 1

Уязвимый графовый агент принимает запрос модели

Уязвимы версии Langroid до 0.65.5 включительно. Для описанного пути нужно повлиять на промпт напрямую или через полученный контент, после чего модель должна вызвать Neo4jChatAgent. В advisory указаны CWE-74 и CVSS 4.0 9,2 (Critical).[1], [2]

Шаг 2

Контент влияет на передаваемый Cypher

До исправления cypher_retrieval_tool передавал msg.cypher_query в read_query, а cypher_creation_tool передавал запрос в write_query. Advisory прослеживает значения до session.run(query, parameters) и tx.run(query, parameters) без промежуточной проверки.[1], [3]

Шаг 3

Права базы определяют непосредственный ущерб

Инструмент чтения может раскрыть данные, доступные подключённой учётной записи; инструмент создания может изменить или удалить данные в пределах этих прав. Advisory также указывает на удалённую загрузку через LOAD CSV. Доступ к файлам или командам ОС зависит от включённых процедур и прав роли.[1]

Шаг 4

В версии 0.65.5 добавлены проверки инструментов

По сообщению сопровождающего, версия 0.65.5 добавляет выключенный по умолчанию allow_dangerous_operations, ограничивает чтение и проверяет опасные операции в обработчиках инструментов. Это дополнительная защита, а не авторизация. Решение сопровождающего и руководство Langroid по SQL-агентам указывают на роли базы данных с минимальными привилегиями как на границу безопасности.[1], [3], [4], [5]

Шаг 5

Обновите пакет и ограничьте права базы

Обновите Langroid до 0.65.5 или новее, проверьте версии в образах и оставьте опасную опцию выключенной. Используйте отдельную роль Neo4j с минимальными правами, выключите ненужные процедуры и ограничьте хост агента.[4], [5]

Исходный код: Уязвимый vs Защищённый вариант

Уязвимый фрагмент следует трассировке advisory; исправленный пример описывает поведение 0.65.5, а не дословный патч. Исправление проверяет запрос на границе инструмента, ограничивает чтение и контролирует опасные действия. Валидатор не является песочницей: ограничьте права Neo4j и изолируйте процесс агента. В документации Langroid указано, что проверки ключевых слов и шаблонов можно обойти; границей контроля должны оставаться права Neo4j.[1], [3], [4], [6]

УЯЗВИМАЯ РЕАЛИЗАЦИЯ
# Уязвимый путь Neo4jChatAgent (Langroid <= 0.65.4).
def cypher_retrieval_tool(self, msg: CypherRetrievalTool):
    query = msg.cypher_query
    return self.read_query(query)

def read_query(self, query: str):
    with self.driver.session() as session:
        return session.run(query, parameters=None)
БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
# В версии 0.65.5 проверка выполняется на границе инструмента, доступной LLM.
def cypher_retrieval_tool(self, msg: CypherRetrievalTool):
    query = msg.cypher_query
    rejection = validate_cypher_query(
        query, is_write=False,
        allow_dangerous=self.config.allow_dangerous_operations,
    )
    if rejection is not None:
        return rejection
    return self.read_query(query)

Чек-лист по защите системы для инженеров

Источники

← AI Security Directory →