FlawOpen

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

● CVE-2026-26030 · CVSS 9.9[1] · Crítica
Investigación · FlawOpen

Semantic Kernel CVE-2026-26030: inyección en filtros

Filtros vectoriales influidos por prompts eludían las comprobaciones AST y llegaban a eval de Python. Actualice a 1.39.4 o posterior.[1], [4]

Vector CVSSCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H[1]
💡 Explicación en Lenguaje Sencillo (ELI5)

Imagina a una bibliotecaria que recibe una tarjeta con una regla de búsqueda, comprueba algunas palabras conocidas y luego pide al ordenador que ejecute la tarjeta como un pequeño programa. Quien pueda influir en la tarjeta puede aprovechar fallos de esa comprobación. CVE-2026-26030 permitía que un filtro influido por el modelo pasara de buscar datos a ejecutar código dentro del proceso de la aplicación.[4]

Conceptos Clave y Términos

InMemoryVectorStore
Almacén vectorial dentro del proceso de Semantic Kernel; la búsqueda puede filtrar registros antes de devolver resultados.[4]
Expresión de filtro
Predicado que decide si un registro puede aparecer en una búsqueda vectorial. En la ruta Python afectada, los filtros de texto se analizaban y evaluaban como expresiones Python.[4]
Árbol de sintaxis abstracta (AST)
Representación estructurada del código analizado. Una validación incompleta puede dejar vías hacia la introspección de objetos Python.[2], [4]
Inyección de prompts
Texto no confiable influye en el modelo para que realice una acción imprevista. El riesgo depende de que la aplicación exponga el filtro vulnerable a entradas del modelo.[4]

Mapeos de marcos

  • Referencia CWE para la debilidad descrita en esta guía: CWE-94

Flujo de Ataque Paso a Paso

Paso 1

Se despliega la ruta de filtro vulnerable

La aplicación usa Semantic Kernel Python anterior a 1.39.4 y filtros de InMemoryVectorStore. Microsoft clasifica el problema como Crítico (CVSS 3.1 9,9; CWE-94) y recomienda 1.39.4 o posterior.[1], [4]

Paso 2

Contenido no confiable influye en el filtro elegido por el modelo

El ataque requiere una vía de inyección de prompts que influya en la entrada del agente y un Search Plugin con el filtro predeterminado de InMemoryVectorStore. Un filtro generado por el modelo no es confiable solo por llegar mediante una llamada tipada.[4]

Paso 3

El filtro se convierte en código Python

Antes de la corrección, el filtro se analizaba como AST y se evaluaba sin builtins, pero las comprobaciones no restringían suficientemente el recorrido del modelo de objetos. La versión 1.39.4 conserva ast.Subscript para acceder a campos de registros y combina la lista de nodos permitidos con el bloqueo de atributos peligrosos, nombres aislados limitados a los parámetros lambda y una lista de llamadas permitidas. El código upstream no rechaza los subíndices por sí solos; eval sin builtins no es un sandbox.[2], [4]

Paso 4

La ejecución alcanza el proceso de la aplicación

Si la expresión elude la validación durante la búsqueda, la lógica influida por el atacante puede ejecutarse en el proceso Python del agente. El alcance depende de los permisos, entorno, credenciales y red de ese proceso.[4]

Paso 5

Corrija el límite del analizador e investigue la exposición

Actualice semantic-kernel a 1.39.4 o posterior. El parche comprueba atributos peligrosos y limita los nombres simples al parámetro lambda; el análisis también documenta listas permitidas AST y de funciones. Investigue anomalías de procesos, red y credenciales durante el periodo afectado.[1], [2], [3], [4]

Código Fuente: Vulnerable vs. Seguro

El panel vulnerable muestra un patrón representativo, no código literal del producto: un valor controlado por el modelo se interpola en sintaxis Python antes de eval. El panel corregido destaca las comprobaciones upstream de 1.39.4. La lista AST configurada incluye ast.Subscript para acceder a campos de registros; el parche la combina con el bloqueo de atributos peligrosos, nombres aislados limitados a lambda y llamadas permitidas. Quitar builtins no convierte eval en un sandbox. Actualice el paquete; no copie este fragmento como validador independiente.[2], [6], [4]

IMPLEMENTACIÓN VULNERABLE
# Patrón representativo anterior al arreglo: el texto del modelo cambia la expresión.
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
PARCHE SEGURO Y ROBUSTO
def validate_filter(self, tree):
    # Comprobaciones upstream de 1.39.4; mensajes de excepción abreviados.
    # Los filtros de nivel superior deben ser expresiones 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 Verificación de Seguridad para Ingeniería

Fuentes

← AI Security Directory →