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]

CVSS 向量CVSS: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
不可信文本影响 AI 模型并诱发非预期操作。风险取决于应用是否将易受攻击的过滤路径暴露给模型输入。[4]

框架映射

  • 本指南所述弱点的 CWE 参考: CWE-94

攻击执行流程分解

步骤 1

部署了易受攻击的过滤路径

应用使用低于 1.39.4 的 Semantic Kernel Python 和 InMemoryVectorStore 过滤器。Microsoft 评为严重(CVSS 3.1 9.9,CWE-94),建议升级至 1.39.4 或更高版本。[1], [4]

步骤 2

不可信内容影响模型选择的过滤器

攻击需要提示词注入影响智能体输入,并使用默认 InMemoryVectorStore 过滤器的 Search Plugin。类型化工具调用不会自动让模型生成的过滤器变可信。[4]

步骤 3

过滤器变成 Python 代码

修复前,过滤器会被解析为 AST,并在移除 builtins 后求值,但原有检查未充分限制对象遍历。1.39.4 仍允许 ast.Subscript 访问记录字段,同时组合使用 AST 节点白名单、危险属性阻止列表、仅允许 lambda 参数作为独立名称,以及函数调用白名单。上游代码并未单独禁止下标访问;移除 builtins 的 eval 也不等于沙箱。[2], [4]

步骤 4

执行进入应用进程

表达式若绕过验证,攻击者影响的逻辑可能在智能体 Python 进程中执行。影响范围受该进程的系统权限、环境、凭据和网络能力限制。[4]

步骤 5

修复解析器边界并排查暴露

升级 semantic-kernel 至 1.39.4 或更高版本。补丁检查危险属性并将裸名称限制为 lambda 参数;同时排查受影响期间的进程、网络和凭据异常。[1], [2], [3], [4]

源代码对比:漏洞与安全实现

易受攻击的代码块是代表性模式,并非产品原始代码:模型控制的值在 eval 前被插入 Python 语法。修复代码块聚焦于上游 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):
    # 上游 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 →