安全设计文档通常在项目启动时写得很认真,代码审查却常常只盯着当前 diff。Dropbox 将模型上下文协议(Model Context Protocol,MCP)与内部知识平台 Dash 集成,在 AI 辅助代码审查期间检索威胁模型和安全要求,让审查者能够直接判断实现是否偏离设计意图。
这项实践解决的重点不是“让模型自动发现所有漏洞”,而是把分散在知识库里的安全约束,及时送到正在审查具体变更的人和 AI 面前。
真正的缺口在设计文档与 PR 之间
传统代码审查可以较好地回答这些问题:
- 输入是否经过验证;
- 权限检查是否存在明显遗漏;
- 敏感信息是否被写入日志;
- 加密、序列化和错误处理是否符合编码规范。
但它不容易仅凭一段 diff 回答另一些问题:
- 该接口原本只允许内部服务调用,为什么现在暴露给了外部客户端?
- 威胁模型是否要求高风险操作进行二次授权?
- 数据设计是否禁止跨租户查询?
- 某个字段是否被明确归类为不得持久化的敏感数据?
这些约束往往存在于威胁模型、安全评审记录或需求文档中。审查者如果不知道文档在哪里,或者没有时间逐页搜索,就只能依据通用安全经验判断。
Dropbox 的思路是利用 Dash 检索内部知识,再通过 MCP 将相关上下文交给 AI 辅助审查流程。这样,审查输入不再只有代码和通用规则,还包含这次变更应该遵守的设计约束。
MCP 在这里承担的是上下文边界
从来源摘要可以确认,系统会针对拉取请求检索威胁模型和安全要求。具体内部组件、排序算法和 MCP 工具定义并未公开,因此不应把某一种实现方式视为 Dropbox 的实际架构。
在类似系统中,可以把流程划分为四个环节:
- 从 PR 提取仓库、目录、服务名、所有者、工单号和变更内容等信号。
- 通过 MCP 工具向企业知识平台发起结构化检索。
- 对结果进行权限过滤、相关性排序,并保留文档来源和版本信息。
- 将代码 diff 与安全上下文一起交给审查模型,要求它逐项验证实现。
MCP 的价值在于定义一条受控的上下文通道。代码审查代理不必了解 Dash 的索引细节,只需调用类似 search_security_context 的工具;知识平台则负责检索、授权和结果结构化。
返回内容也不应该只是一大段文本。更适合审查的结果可以包含:
- 安全要求的稳定标识;
- 适用服务和代码路径;
- 要求级别,例如必须、建议或例外;
- 文档版本与更新时间;
- 可供审查者核验的原始出处;
- 检索置信度或匹配依据。
这类结构能让模型给出“AUTH-017 可能未满足”的结论,而不是泛泛地提示“请注意鉴权”。
一个可运行的最小原型
下面不是 Dropbox 内部实现,而是一个可以这样实践的最小原型。它使用 Python 标准库模拟“根据 PR 元数据检索安全要求”的服务。生产环境中,可以把 /security-context 封装成 MCP 工具,并将内置文档替换为 Dash 或其他企业搜索接口。
将以下内容保存为 server.py,需要 Python 3.10 或更高版本:
import json
from http.server import BaseHTTPRequestHandler, HTTPServer
REQUIREMENTS = [
{
"id": "AUTH-017",
"services": ["billing-api"],
"paths": ["src/refunds/", "src/admin/"],
"severity": "must",
"text": "Refund operations require both tenant isolation and an admin role check.",
"source": "billing threat model v4",
},
{
"id": "DATA-009",
"services": ["billing-api", "reporting-worker"],
"paths": ["src/", "jobs/"],
"severity": "must",
"text": "Do not write payment tokens or full request bodies to logs.",
"source": "payment data handling standard v2",
},
]
def retrieve(service: str, changed_files: list[str]) -> list[dict]:
matches = []
for requirement in REQUIREMENTS:
service_match = service in requirement["services"]
path_match = any(
filename.startswith(prefix)
for filename in changed_files
for prefix in requirement["paths"]
)
if service_match and path_match:
matches.append(requirement)
return matches
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
if self.path != "/security-context":
self.send_error(404)
return
length = int(self.headers.get("Content-Length", "0"))
payload = json.loads(self.rfile.read(length))
requirements = retrieve(
payload["service"],
payload.get("changed_files", []),
)
response = json.dumps(
{
"pull_request": payload.get("pull_request"),
"requirements": requirements,
}
).encode()
self.send_response(200)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(response)))
self.end_headers()
self.wfile.write(response)
if __name__ == "__main__":
print("Listening on http://127.0.0.1:8080")
HTTPServer(("127.0.0.1", 8080), Handler).serve_forever()
启动服务:
python3 server.py
在另一个终端模拟 PR 审查代理发起检索:
curl -s http://127.0.0.1:8080/security-context \
-H 'Content-Type: application/json' \
-d '{
"pull_request": 4821,
"service": "billing-api",
"changed_files": [
"src/refunds/create.py",
"src/logging/request_logger.py"
]
}' | python3 -m json.tool
检索结果随后可以和 diff 一起送入审查模型。提示词需要约束模型逐项引用要求,并明确区分证据、疑点和无法验证的内容:
你是一名安全代码审查者。
输入包括一个代码 diff,以及从内部知识库检索出的安全要求。
对每条要求执行以下操作:
1. 标记为 satisfied、violated 或 insufficient_evidence。
2. 引用具体要求 ID 和相关代码行。
3. 只在代码证据充分时判定 violated。
4. 不得把检索结果之外的公司策略臆测为强制要求。
5. 如果要求可能已经过期或与变更无关,交由人工确认。
输出 JSON,不要自动批准或拒绝 PR。
这个原型还缺少真正的 MCP 传输、身份认证和向量检索,但它已经展示了关键数据流:PR 信号进入检索层,结构化安全要求进入审查层,最终结论仍交给审查者确认。
难点不只在检索准确率
把内部文档接入 AI 审查会引入几类新的工程风险。
权限继承。 审查代理只能读取发起者本来有权访问的文档。否则,一条看似无害的 PR 可能成为查询受限架构信息的入口。
文档时效性。 过期威胁模型可能产生错误建议。返回结果应携带版本、更新时间和所有者,对过旧文档降低置信度或要求人工复核。
提示注入。 知识库文档属于不可信输入。审查系统应将其视为参考数据,禁止文档内容改写系统指令、调用任意工具或触发合并操作。
可追溯性。 每条审查意见都应关联要求 ID、文档版本和代码位置。无法追溯的 AI 结论很难进入正式安全流程。
召回噪声。 返回十几篇“可能相关”的文档会挤占上下文并稀释重点。实践中应优先利用服务目录、代码所有权和工单关联缩小范围,再进行语义检索。
从建议模式开始落地
接入这类能力时,不宜立即把 AI 结论设置为合并门禁。更稳妥的落地顺序是:
- 先以只读、仅建议模式运行,记录命中的要求和人工采纳情况。
- 建立小规模金标准 PR 集合,分别测量检索召回率与审查判断准确率。
- 要求意见必须附带文档出处和代码证据,避免无法核验的安全警告。
- 为误报、过期文档和权限问题提供反馈入口,并明确知识条目的负责人。
- 只有在高风险且规则稳定的场景中,才考虑把确定性检查升级为阻断条件。
Dropbox 的实践说明,AI 代码审查的效果不仅取决于模型能力,也取决于它能否在正确时间获得正确的组织知识。MCP 提供标准化的连接方式,Dash 提供内部知识检索,而真正决定系统可信度的,仍是权限、版本、引用和人工复核这些工程约束。