flawopen.com/AI Security/semantic-kernel-inmemory-vector-filter-cve-2026-26030
Semantic Kernel CVE-2026-26030: инъекция в фильтр
Фильтры, на которые влиял промпт, обходили AST-проверки и доходили до Python eval. Обновитесь до версии 1.39.4 или новее.[1], [4]
Представьте библиотекаря, который получает карточку с правилом поиска, проверяет знакомые слова и просит компьютер выполнить карточку как программу. Тот, кто влияет на карточку, может воспользоваться пробелами проверки. CVE-2026-26030 позволяла фильтру, на который влияла модель, перейти от поиска к выполнению кода в процессе приложения.[4]
Ключевые понятия и термины
InMemoryVectorStore- Векторное хранилище внутри процесса Semantic Kernel. Поиск может отфильтровать записи до возврата результатов.[4]
Filter expression- Предикат определяет, попадёт ли запись в результат поиска. В уязвимом Python-пути строковый фильтр разбирался и выполнялся как выражение Python.[4]
Abstract Syntax Tree (AST)- Структурированное представление кода. Неполная проверка AST может оставить пути к интроспекции объектов Python.[2], [4]
Prompt injection- Недоверенный текст влияет на модель и вызывает непредусмотренное действие. Риск возникает, если приложение передаёт модельный ввод уязвимому фильтру.[4]
Связи со стандартами
- Ссылка CWE для слабого места, описанного в этом руководстве: CWE-94
Пошаговый сценарий атаки
Недоверенные данные влияют на фильтр модели
Нужны инъекция промпта, влияющая на ввод агента, и Search Plugin со стандартным фильтром InMemoryVectorStore. Типизированный вызов инструмента не делает созданный моделью фильтр доверенным.[4]
Фильтр становится кодом Python
До исправления фильтр разбирался как AST и выполнялся без builtins, но проверки недостаточно ограничивали обход объектной модели. В версии 1.39.4 ast.Subscript оставлен для доступа к полям записей; вместе с ним используются список разрешённых узлов, блок-лист опасных атрибутов, ограничение свободных имён параметрами lambda и список разрешённых вызовов. Upstream-код не запрещает индексы сами по себе; eval без builtins не является песочницей.[2], [4]
Выполнение достигает процесса приложения
При обходе проверки логика под контролем атакующего может выполниться в процессе Python агента. Доступ ограничивают права ОС, окружение, учётные данные и сеть этого процесса.[4]
Исходный код: Уязвимый vs Защищённый вариант
Уязвимая панель показывает типовой шаблон, а не буквальный исходный код продукта: значение под управлением модели вставляется в синтаксис Python до eval. Исправленная панель выделяет проверки upstream из версии 1.39.4. Настроенный список AST включает ast.Subscript для доступа к полям записей; исправление сочетает его с блокировкой опасных атрибутов, ограничением свободных имён параметрами lambda и списком разрешённых вызовов. Удаление builtins не превращает eval в песочницу. Обновите пакет и не копируйте этот фрагмент как самостоятельный валидатор.[2], [6], [4]
# Типовой шаблон до исправления: текст модели меняет выражение.
filter_text = f"lambda x: x.city == '{model_selected_city}'"
tree = ast.parse(filter_text, mode="eval")
code = compile(tree, filename="<filter>", mode="eval")
filter_fn = eval(code, {"__builtins__": {}}, {}) # nosec
def validate_filter(self, tree):
# Основные проверки upstream 1.39.4; сообщения исключений сокращены.
# Фильтры верхнего уровня должны быть lambda-выражениями.
if not (isinstance(tree, ast.Expression) and isinstance(tree.body, ast.Lambda)):
raise VectorStoreOperationException("Filter must be a lambda expression")
lambda_param_names = {arg.arg for arg in tree.body.args.args}
for node in ast.walk(tree):
if type(node) not in self.allowed_filter_ast_nodes:
raise VectorStoreOperationException("AST node type is not allowed")
if isinstance(node, ast.Attribute) and node.attr in self.blocked_filter_attributes:
raise VectorStoreOperationException("Dangerous attribute is not allowed")
if isinstance(node, ast.Name) and node.id not in lambda_param_names:
raise VectorStoreOperationException("Only lambda parameter names are allowed")
if isinstance(node, ast.Call):
if isinstance(node.func, ast.Name):
func_name = node.func.id
elif isinstance(node.func, ast.Attribute):
func_name = node.func.attr
else:
func_name = None
if func_name and func_name not in self.allowed_filter_functions:
raise VectorStoreOperationException("Function is not allowed")
code = compile(tree, filename="<filter>", mode="eval")
func = eval(code, {"__builtins__": {}}, {}) # nosec
Чек-лист по защите системы для инженеров
- ✓Найдите все среды Python с semantic-kernel и запишите версии, включая контейнеры, notebooks, workers и CI-образы.[4]
- ✓Обновите пакет до 1.39.4 или новее, пересоздайте lock-файлы и пересоберите образы.[1], [3]
- ✓До обновления отключите фильтр InMemoryVectorStore в production — это временная рекомендация поставщика.[1]
- ✓В каждый PR, добавляющий или меняющий фильтр векторного поиска, включайте тесты, подтверждающие, что пользовательский текст, извлечённые данные и аргументы модели не меняют разобранную структуру фильтра; неподдерживаемые формы должны отклоняться.[4]
- ✓Добавьте тест на отклонение опасных AST-атрибутов и имён вне lambda-параметра, без исполняемых payload.[2]
- ✓Представляйте выбранные моделью фильтры типизированными данными с явными списками разрешённых полей и операторов; добавьте тесты, отклоняющие строки-выражения и неизвестные поля или операторы.
- ✓Ограничьте агенту доступ к файлам, сети и учётным данным.[4]
- ✓Добавьте регрессионный тест обнаружения на хосте агента: он должен создавать типовые события дочернего процесса и исходящего соединения и проверять, что действующее правило телеметрии поднимает оба оповещения.[4]