site logo

Marico's space

前沿模型安全审计:Simon Willison 和 Alex Garcia 如何用 Claude 和 GPT 找出 Datasette 细微 Bug

AI技术与应用 2026-09-15 17:34:39 16

Simon Willison 和 Alex Garcia 刚刚发布了 Datasette 的两个安全版本(1.0a39 和 0.65.4),整个过程是一次彻底的 AI 辅助安全审计。事情起源于 Sevban Dönmez 报告的几个问题,后来演变成持续一周的协作——用 Claude Fable 5.1、GPT-5.6 和 GPT-6 Astra 来排查那些混合了公开表和私有表访问模式的授权 Bug。Willison 明确表示,以后所有开发工作都会加入前沿模型的安全审计流程。这算是 AI 代理安全研究正式进入生产工作流的真实案例了。

有意思的地方不在于 LLM(大语言模型)能发现 Bug,而在于整个工作流:人机怎么分工、怎么确保每个问题都有两个独立审查者、以及怎么设计提示词来挖掘那些细微的授权逻辑错误。

工作流:人机职责划分

Willison 和 Garcia 在一个私有的共享仓库里协作。大多数问题的处理流程是这样的:

  • 一个人写自动化测试,重现安全问题的场景
  • 另一个人负责实现修复
  • 两个人都要审查每个问题,再加上运行不同模型的编码 AI

这种模式保证了测试编写和修复实现是独立的。如果同一个人既写测试又写修复,可能会把自己的思维模型同时编码进两个产物里。分开来做,就能得到对安全需求的两种独立理解。

模型负责跑初轮审计。人类负责验证、写测试、实现修复。模型不直接写生产代码,它们负责识别攻击面和潜在漏洞。

跨模型验证实践

他们用三个不同的前沿模型跑了同样的审计:

  • Claude Fable 5.1
  • GPT-5.6
  • GPT-6 Astra

每个模型的训练数据、推理模式、盲区都不一样。用多个模型跑同一套审计能提高覆盖率。如果三个模型都标记了同一个问题,那大概率是真的。如果只有一个模型标记,就需要人工仔细审查,判断是假阳性还是其他模型漏掉的细微 Bug。

这不是集成投票,而是把模型多样性当作纵深防御。每个模型都是独立的审查者,用自己的视角来看代码库。

模型发现了什么:混合公开/私有表的授权 Bug

这些 Bug 被描述为"非常细微",涉及公开表和私有表的混合场景。Datasette 允许把某些表配置为公开,另一些配置为私有。当查询涉及两种类型的表时,授权逻辑需要正确执行访问控制。

这类授权 Bug 可能包括:

  • 通过与公开表的联表查询泄露私有表数据
  • 在聚合公开表和私有表数据时绕过权限检查
  • 通过错误信息或 API 响应暴露私有表的元数据(列名、行数等)
  • 允许未认证用户通过时序攻击或查询行为推断私有表的存在

模型可能是通过分析公开表和私有表逻辑交叉的代码路径来发现这些问题的。前沿模型擅长追踪复杂条件语句中的数据流,也能发现授权检查缺失或顺序错误的场景。

授权审计的提示词结构和上下文

Willison 没有公布具体的提示词,但从结果可以推断出结构。有效的授权 Bug 安全审计提示词需要:

  1. 完整的代码库上下文:模型需要看到整个授权层,而不是孤立的函数。这意味着要么用大上下文窗口,要么对代码库进行智能分块。

  2. 明确的威胁模型:提示词要明确说明你要防御什么。对 Datasette 来说,就是防止未认证用户或低权限用户访问私有表数据。

  3. 示例攻击模式:提供常见授权 Bug 的例子(IDOR、权限提升、信息泄露),让模型知道要找什么。

  4. 聚焦边界条件:让模型专门检查公开和私有数据交互的代码路径、权限变更的地方、用户输入影响授权决策的地方。

一个合理的提示词结构大概是这样的:

You are auditing a Python web application for authorization vulnerabilities. **Threat model**: An unauthenticated user should not be able to access data from tables marked as private. A low-privilege user should not be able to escalate their permissions. **Focus areas**:
- Code paths where public and private tables are queried together
- Permission checks in API endpoints
- Error messages that might leak information about private tables
- Query construction logic that uses user input **Common patterns to look for**:
- Missing authorization checks before database queries
- Authorization checks that happen after data is fetched
- Logic errors in permission inheritance or delegation
- Information disclosure through error messages, timing, or metadata Review the following code and identify potential authorization vulnerabilities.
For each issue, explain the attack scenario and the affected code path. [Insert codebase or relevant modules here]

架构:如何融入开发工作流

审计工作流是这样的:

┌─────────────────┐
│ Security Issue │
│ Reported │
└────────┬────────┘ │ ▼
┌─────────────────┐
│ Run AI Audit │
│ (3 models) │
└────────┬────────┘ │ ▼
┌─────────────────┐
│ Human Review │
│ of Findings │
└────────┬────────┘ │ ▼
┌─────────────────┐
│ Split Work: │
│ Person A writes │
│ test, Person B │
│ implements fix │
└────────┬────────┘ │ ▼
┌─────────────────┐
│ Both Humans │
│ Review Fix │
└────────┬────────┘ │ ▼
┌─────────────────┐
│ Ship Security │
│ Release │
└─────────────────┘

关键决策点:

  • 何时触发审计:收到安全报告后、重大版本发布前、或者定期(比如每季度)。
  • 如何划定审计范围:全代码库、特定模块、或者静态分析工具标记的区域。
  • 如何验证发现:必须有人工审查。模型会产生假阳性。不是每个标记的问题都可利用。
  • 如何跟踪修复:使用私有 issue 跟踪器。在修复发布之前不要公开安全发现。

权衡和风险

方面 收益 风险
多模型 覆盖率提高,视角多样化 成本更高,需要排查更多假阳性
测试/修复分工 独立验证,发现实现错误 比一个人同时做更慢,需要协调
AI 生成的结果 发现人类遗漏的细微 Bug,可扩展到大代码库 假阳性,可能遗漏依赖上下文的漏洞
私有仓库 在修复前保持发现保密 需要纪律约束避免在公开提交中泄露细节
需要人工审查 验证可利用性,确定修复优先级 如果假阳性太多,人会成为瓶颈

最大的风险是对模型输出的过度依赖。模型擅长模式匹配,但不擅长理解业务逻辑和真实世界的可利用性。一个被标记的问题可能在技术上是正确的,但由于其他缓解措施(限速、网络隔离、输入验证)实际上不可利用。

可观测性和失败模式

需要追踪:

  • 每个模型的假阳性率:哪些模型产生的噪音最多?调整提示词或淘汰噪音大的模型。
  • 排查发现的时间:人类验证每个发现需要多长时间?如果排查时间比写测试和修复还长,工作流就出问题了。
  • 覆盖率:模型是否在所有模块都发现了问题,还是偏向某些代码模式?
  • 修复验证:修复是否真正关闭了漏洞?修复后重新跑审计确认。

失败模式:

  • 模型捏造漏洞:被标记的代码实际上是安全的。人工审查能发现,但浪费了时间。
  • 模型漏掉真实漏洞:模型不理解授权逻辑或攻击面。这就是为什么要用多个模型和人工审查。
  • 修复引入新 Bug:实现修复的人误解了问题或者破坏了其他东西。这就是为什么另一个人要先写测试。
  • 发现在修复前泄露:有人不小心把细节提交到公开仓库或者在公开场合讨论。使用私有仓库,必要时签 NDA。

代码示例:为一个授权 Bug 编写测试

这可能是一个 Datasette 测试套件中用于混合公开/私有表授权 Bug 的测试:

import pytest
from datasette.app import Datasette @pytest.mark.asyncio
async def test_private_table_not_leaked_via_join(): """ Ensure that joining a public table with a private table does not leak private table data to unauthenticated users. """ ds = Datasette( memory=True, metadata={ "databases": { "test": { "tables": { "public_table": {"allow": True}, "private_table": {"allow": {"id": "admin"}}, } } } }, ) # Populate tables
 db = ds.add_memory_database("test") await db.execute_write("CREATE TABLE public_table (id INTEGER, name TEXT)") await db.execute_write("CREATE TABLE private_table (id INTEGER, secret TEXT)") await db.execute_write("INSERT INTO public_table VALUES (1, 'Alice')") await db.execute_write("INSERT INTO private_table VALUES (1, 'classified')") # Attempt to join as unauthenticated user
 response = await ds.client.get( "/test.json?sql=SELECT public_table.name, private_table.secret " "FROM public_table JOIN private_table ON public_table.id = private_table.id" ) # Should return 403 Forbidden, not the joined data
 assert response.status_code == 403 assert "private_table" not in response.text

这个测试重现了攻击场景:一个未认证用户试图通过与公开表联表来访问私有表数据。如果查询成功或者响应泄露了私有表信息,测试就会失败。

技术结论

适合使用这种工作流的场景:

  • 维护有复杂授权逻辑的 Web 应用
  • 有预算跑多个前沿模型(根据代码库大小,每次审计预计花费 50-500 美元)
  • 至少有两名工程师可以分工写测试和实现修复
  • 愿意排查假阳性(预计假阳性率 30-50%)
  • 需要审计大型代码库,而人工审查不现实

不适合使用这种工作流的场景:

  • 授权逻辑简单,已有基于属性的测试覆盖
  • 承担不了分工测试/修复的协调开销
  • 没有具备安全专业知识的人来验证发现
  • 代码库太大,超出当前模型的上下文窗口(虽然可以分块处理)
  • 需要实时安全反馈(这是批量审计流程,不是持续监控)

核心洞察是:模型擅长发现潜在问题,但验证可利用性和实现修复必须靠人。分工模式确保了独立审查,同时不会让总工作量翻倍。如果你已经在做人工安全审计,加入 AI 辅助审计能以合理成本提高覆盖率。如果你根本没有在做安全审计,先从人工审查开始,建立对威胁模型的直觉,等理解了业务逻辑再加入 AI 辅助。