FlawOpen

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

● CVE-2026-26030 · CVSS 9.9[1] · Crítica
Pesquisa · FlawOpen

Semantic Kernel CVE-2026-26030: injeção em filtros

Filtros vetoriais influenciados por prompts contornavam as verificações AST e chegavam ao eval do Python. Atualize para 1.39.4 ou superior.[1], [4]

Vetor CVSSCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[1]
💡 Explicação em Linguagem Simples (ELI5)

Imagine uma bibliotecária que recebe um cartão com uma regra de busca, verifica algumas palavras conhecidas e depois manda o computador executar o cartão como um pequeno programa. Quem pode influenciar o cartão pode explorar falhas nessa verificação. A CVE-2026-26030 permitia que um filtro influenciado pelo modelo passasse da consulta de dados à execução de código no processo da aplicação.[4]

Conceitos Centrais e Termos

InMemoryVectorStore
Armazenamento vetorial no processo do Semantic Kernel; a busca pode filtrar registros antes de retornar resultados.[4]
Expressão de filtro
Predicado que decide se um registro pode aparecer nos resultados da busca vetorial. No caminho Python afetado, filtros em texto eram analisados e avaliados como expressões Python.[4]
Árvore Sintática Abstrata (AST)
Representação estruturada do código analisado. Uma validação incompleta pode deixar caminhos para introspecção de objetos Python.[2], [4]
Injeção de prompt
Texto não confiável influencia o modelo a realizar uma ação não prevista. O risco depende de a aplicação expor o filtro vulnerável à entrada controlada pelo modelo.[4]

Mapeamentos de frameworks

  • Referência CWE para a fraqueza descrita neste guia: CWE-94

Fluxo de Ataque Passo a Paso

Passo 1

O caminho de filtro vulnerável está implantado

A aplicação usa Semantic Kernel Python anterior à 1.39.4 e filtros do InMemoryVectorStore. A Microsoft classifica o problema como Crítico (CVSS 3.1 9,9; CWE-94) e recomenda a versão 1.39.4 ou superior.[1], [4]

Passo 2

Conteúdo não confiável influencia o filtro escolhido pelo modelo

O ataque exige um caminho de injeção de prompt que influencie a entrada do agente e um Search Plugin com o filtro padrão do InMemoryVectorStore. Uma expressão gerada pelo modelo não é confiável só por vir de uma chamada de ferramenta tipada.[4]

Passo 3

O filtro vira código Python

Antes da correção, o filtro era analisado como AST e avaliado sem builtins, mas as verificações não restringiam suficientemente o acesso ao modelo de objetos. A versão 1.39.4 mantém ast.Subscript para acessar campos dos registros e combina a lista de nós permitidos com o bloqueio de atributos perigosos, nomes isolados restritos aos parâmetros lambda e uma lista de chamadas permitidas. O código upstream não rejeita subscritos por si só; eval sem builtins não é um sandbox.[2], [4]

Passo 4

A execução chega ao processo da aplicação

Se a expressão contornar a validação durante a busca, lógica influenciada pelo atacante pode executar no processo Python do agente. O acesso fica limitado às permissões, ambiente, credenciais e alcance de rede desse processo.[4]

Passo 5

Corrija a fronteira do parser e investigue a exposição

Atualize semantic-kernel para 1.39.4 ou superior. O patch verifica atributos perigosos e restringe nomes isolados ao parâmetro lambda; a análise também documenta listas permitidas de nós AST e funções. Investigue anomalias de processos, rede e credenciais no período afetado.[1], [2], [3], [4]

Código-Fonte: Vulnerável vs. Seguro

O painel vulnerável mostra um padrão representativo, não o código literal do produto: um valor controlado pelo modelo é interpolado na sintaxe Python antes de eval. O painel seguro destaca as verificações upstream da versão 1.39.4. A lista de AST configurada inclui ast.Subscript para acessar campos dos registros; o patch combina essa lista com o bloqueio de atributos perigosos, nomes isolados limitados a lambda e chamadas permitidas. Remover builtins não transforma eval em sandbox. Atualize o pacote; não copie este trecho como validador independente.[2], [6], [4]

IMPLEMENTAÇÃO VULNERÁVEL
# Padrão representativo anterior à correção: o texto do modelo altera a expressão.
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
PATCH SEGURO E ROBUSTO
def validate_filter(self, tree):
    # Verificações upstream 1.39.4 em foco; mensagens de exceção abreviadas.
    # Filtros no nível superior devem ser expressões 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

Lista de Verificação de Segurança para Engenharia

Fontes

← AI Security Directory →