FlawOpen

flawopen.com/参考资料/PR 机器人安全

AI PR 审查机器人:Prompt Injection 与 SSRF 防护

AI PR 审查机器人:防止 Prompt Injection 导致 SSRF

说明不可信 Pull Request 文本如何影响 AI 工具,以及如何限制机器人权限和网络访问。

安全风险 CWE-1427 / CWE-918 AI 与开发工作流安全

通俗解释:持有公司网络通行证的审查助手

Pull Request 就像交给审查团队的包裹:其中的内容可能有用,但不会因此成为公司的政策。如果 AI 审查助手还能从私有网络获取任意 URL,误导性指令就可能影响它访问的目标。风险取决于工具和网络权限;仅仅读取恶意文本不会自动获得网络访问权。

核心概念与关键术语

不可信输入:
贡献者提交的 Pull Request 标题、描述、评论、差异和链接内容。
间接 Prompt Injection:
不可信文本进入模型上下文后影响智能体。
SSRF 边界:
服务端获取工具可能访问贡献者无法直接访问的目标。
影响条件:
还必须存在可访问的内部服务、可用凭据,以及不足的授权或出站网络控制。

机制与根因

审查机器人可能把贡献者控制的文本与可信的审查指令一并提供给模型。模型可能根据任一内容提出工具调用。提示词和分隔符不能授权网络访问。只有当应用代码接受模型选择的目标,并且联网工具能够访问该目标时,才会出现 SSRF。云元数据或凭据访问是额外的条件性影响,并非 Prompt Injection 的必然结果。

有条件的攻击路径

1

贡献者控制 PR 内容

外部贡献者可以影响标题、描述、评论、修改文本和链接内容。

2

智能体读取内容

服务将部分不可信字段放入模型上下文,这可能影响回答或工具调用建议。

3

工具能力决定可达范围

若智能体可获取任意 URL,运行器可能联系网络路径允许的目标。没有该工具,就不存在此 SSRF 路径。

4

影响取决于部署

只有当可访问服务、元数据设置、身份权限和输出控制都允许时,内部数据或凭据才可能暴露。

代码:未经检查的调用与授权读取

惰性模拟调用
# INERT DEMO: model-selected URL reaches a mock tool without policy checks
from dataclasses import dataclass

@dataclass
class ToolCall:
    name: str
    arguments: dict[str, str]

class MockFetch:
    def __init__(self):
        self.calls = []

    def __call__(self, url: str) -> str:
        self.calls.append(url)
        return "fixture response"

def dispatch_unchecked(call: ToolCall, tools: dict):
    # The mock records a string; it makes no network request.
    return tools[call.name](**call.arguments)

mock_fetch = MockFetch()
call = ToolCall("fetch_url", {"url": "https://docs.example.invalid/"})
assert dispatch_unchecked(call, {"fetch_url": mock_fetch}) == "fixture response"
assert mock_fetch.calls == ["https://docs.example.invalid/"]
经策略授权的只读工具
# SAFE DEMO: the agent receives only a read-only PR capability
from dataclasses import dataclass

@dataclass(frozen=True)
class ReviewContext:
    repository: str
    pull_request: int

@dataclass
class ToolCall:
    name: str
    arguments: dict[str, object]

READ_ONLY_TOOLS = {"read_pr_diff"}

def dispatch_review_call(call: ToolCall, context: ReviewContext, policy, tools):
    if call.name not in READ_ONLY_TOOLS:
        raise PermissionError("Tool is not available to this review")
    expected = {"repository": context.repository,
                "pull_request": context.pull_request}
    if call.arguments != expected:
        raise ValueError("Arguments must match the authorized review")
    if not policy.can_read_pr(context.repository, context.pull_request):
        raise PermissionError("Review principal cannot read this pull request")
    # The injected read_pr_diff function is trusted app code, not model output.
    return tools["read_pr_diff"](**expected)

工程加固清单

相关的已记录漏洞 — CVE-2023-32786

GitHub 审核的 CVE-2023-32786 公告指出,0.0.329 之前的 LangChain 中,Prompt Injection 可迫使服务获取任意 URL(SSRF),并可能影响后续任务。公告将 0.0.329 列为修复版本。这是已记录的 URL 获取攻击链,并不能证明发生过 PR 机器人事件或云元数据被窃取。

主要来源与指南

浏览安全目录 → 浏览其他参考指南 →
另请参阅 服务器端请求伪造(SSRF,CWE-918):原理以及在各语言中的防御方法 — flawopen.com Node.js fetch() SSRF:安全获取远程 URL SSRF 与云元数据:凭据风险和防护措施