FlawOpen

flawopen.com/AI Security/semantic-kernel-inmemory-vector-filter-cve-2026-26030

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

Semantic Kernel CVE-2026-26030: инъекция в фильтр

Фильтры, на которые влиял промпт, обходили AST-проверки и доходили до Python eval. Обновитесь до версии 1.39.4 или новее.[1], [4]

Вектор CVSSCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[1]
💡 Простыми словами (ELI5)

Представьте библиотекаря, который получает карточку с правилом поиска, проверяет знакомые слова и просит компьютер выполнить карточку как программу. Тот, кто влияет на карточку, может воспользоваться пробелами проверки. 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

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

Шаг 1

Развёрнут уязвимый путь фильтрации

Приложение использует Semantic Kernel Python до 1.39.4 и фильтр InMemoryVectorStore. Microsoft указывает Critical, CVSS 3.1 9,9 и CWE-94; исправление — версия 1.39.4 или новее.[1], [4]

Шаг 2

Недоверенные данные влияют на фильтр модели

Нужны инъекция промпта, влияющая на ввод агента, и Search Plugin со стандартным фильтром InMemoryVectorStore. Типизированный вызов инструмента не делает созданный моделью фильтр доверенным.[4]

Шаг 3

Фильтр становится кодом Python

До исправления фильтр разбирался как AST и выполнялся без builtins, но проверки недостаточно ограничивали обход объектной модели. В версии 1.39.4 ast.Subscript оставлен для доступа к полям записей; вместе с ним используются список разрешённых узлов, блок-лист опасных атрибутов, ограничение свободных имён параметрами lambda и список разрешённых вызовов. Upstream-код не запрещает индексы сами по себе; eval без builtins не является песочницей.[2], [4]

Шаг 4

Выполнение достигает процесса приложения

При обходе проверки логика под контролем атакующего может выполниться в процессе Python агента. Доступ ограничивают права ОС, окружение, учётные данные и сеть этого процесса.[4]

Шаг 5

Исправьте парсер и исследуйте возможную компрометацию

Обновите semantic-kernel до 1.39.4 или новее. Патч проверяет опасные атрибуты и разрешает имена только для параметра lambda; изучите аномалии процессов, сети и учётных данных за уязвимый период.[1], [2], [3], [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

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

Источники

← AI Security Directory →