Codex-Security:基于 AI Agent 的代码审计框架
一、Codex Security 简介
Codex Security 是一套基于 Codex Agent 的代码安全审计工具。本文基于 @openai/codex-security 0.1.14 版本 SDK,梳理其代码设计和运行过程。
传统静态分析工具(Fortify、CodeQL)把源码抽象成 AST 或数据流图,再用预定义规则匹配已知漏洞模式。这种规则匹配模式存在两个严重问题:
- 漏报:规则是死的,业务逻辑漏洞、跨组件授权缺陷、状态机绕过落在规则覆盖之外;
- 误报:规则只认模式不认语义,长得像漏洞的代码一律报警,海量假告警淹没真问题。
Codex Security 充分利用 LLM 灵活强大的语义理解能力:阅读源码、建立威胁地图、验证安全问题,全流程由 AI Agent 自动完成,无需编译源码、不用构建 AST、不用编写规则。
1. 一次扫描过程
Codex Security 执行一次审计扫描通常包含以下步骤:
graph LR
A[目标绑定] --> B[威胁建模]
B --> C[漏洞发现]
C --> D[证据验证]
D --> E[攻击路径分析]
E --> F[结果生成]
- 目标绑定:确定仓库、指定路径、Git revision、working tree 或 diff;
- 威胁建模:识别资产、入口点、信任边界、攻击者能力和关键控制;
- 漏洞发现:从外部输入、权限边界和敏感操作中寻找安全问题;
- 证据验证:检查 attacker、source、control、sink、前置条件和反证;
- 攻击路径分析:确认问题是否真实可达,并校准影响、置信度和严重性;
- 结果生成:输出结构化 JSON,再由确定性代码完成校验,并生成报告。
2. 三种扫描工作流
Codex Security CLI 支持三种扫描模式:standard、deep 和 diff。三种模式的简要对比如下:
| 维度 | Standard(默认) | Deep | Diff |
|---|---|---|---|
| 触发方式 | scan .,可配合 --path |
scan . --mode deep,可配合 --path |
scan . --diff origin/main 或 scan . --working-tree |
| 扫描对象 | 整个仓库或指定路径 | 整个仓库或指定目录 | commit、分支差异或本地修改 |
| 工作方式 | 一次完整审计,按需并行调查 | 重复执行多个完整 Standard,再语义归并 | 审查所有变更源码 |
| 耗时 | 低到中 | 高,discovery 最长 96 小时(可提前结束) | 通常较低,取决于 diff 和验证方式 |
| 适用场景 | 日常审计、模块检查 | 关键发布、高价值资产、安全验收 | PR、CI、commit 和 working tree 审查 |
| 覆盖表达 | 语义化 coverage 和已审文件计数 | 聚合已完成的 Standard,未完成工作标记为 partial/deferred | 所有变更源码和候选都必须被处理,未解决项标记 deferred |
二、Codex Security 代码结构
1. 两类代码
Codex Security 的代码可分为两部分:一部分是传统代码逻辑,调用关系确定;另一部分是用自然语言写成的 Agent 工作流(skills/*.md 等),执行逻辑由 LLM 控制,调用关系和执行结果存在一定的不确定性。
graph TD
subgraph WA[确定性代码]
A1[src/*.ts CLI、SDK、事件处理]
A2[scripts/*.py Workbench、校验、报告生成]
A3[SQLite 扫描和 Finding 状态]
A4[MCP Runtime 工具适配]
end
subgraph WB[Agent 工作流]
B1[skills/*.md 工作流定义]
B2[references/*.md 审查规则与数据契约]
B3[LLM 阅读源码、委派任务、产生草稿]
end
WA -->|Prompt、环境变量、MCP 工具| WB
WB -->|事件流、工具调用、产物文件| WA
2. Standard 运行过程
以 Standard 模式的扫描为例:
1 | codex-security scan ./my-repo |
阶段一:准备工作
1 | bin/codex-security.mjs |
run() 主要完成四件事:
1 | ① 绑定扫描目标 |
环境变量提供 Agent 运行时的上下文,主要包括:
1 | CODEX_SECURITY_SCAN_ID |
阶段二:启动 Agent
startThread() 创建 Codex thread,runStreamed() 启动推理并持续接收 Codex Runtime 返回的事件流:
1 | const thread = codex.startThread({ |
runScanEvents() 中按事件类型分发处理:
1 | Codex Agent |
如果事件流提前断开,却没有收到 turn.completed,会认为本次执行不完整,不会直接把扫描标记为完成。
Codex 的工作目录为扫描输出目录,被审查仓库以绝对路径传入。默认权限设置为:
1 | 文件系统根目录 只读 |
阶段三:Agent 内部审计
第 0 步:能力预检
Standard 在审查源码前,会检查当前 Codex 运行环境是否支持预定的多 Agent 工作流,主要包括:
- 是否能够创建子 Agent;
- 是否有足够的 worker 槽位。Standard 推荐配置为 6 个可用槽位,用于同时运行一个 baseline auditor 和多个 focused investigator。
预检通过后,再开始代码审计。
第 1 步:建立审计上下文
父 Agent 读取以下文件,并根据源码建立威胁地图,定位入口点、信任边界、敏感操作和安全控制:
security-scan/SKILL.md;references/core-scan.md;- 适用目录中的
SECURITY.md; - 用户上下文;
- 可选威胁模型和知识库。
SKILL.md 和 core-scan.md 定义了 Standard 的审计算法和运行流程,LLM 是它的执行引擎。
第 2 步:启动 baseline auditor
父 Agent 启动一个 baseline auditor:
1 | fork_turns: "none" // 子 Agent 不继承父会话历史 |
auditor 不接收父 Agent 生成的威胁地图,它根据独立 prompt 从头检查目标源码。这种设计是为了避免所有 worker 都围绕同一组预设展开调查,减少”先入为主”造成的漏报。
第 3 步:派发 focused investigators
父 Agent 将安全问题整理为 investigation packets,再根据工作量决定 investigator 数量。
investigator 可以从不同方向对源码展开调查:
1 | Forward 从外部输入追向敏感操作 |
investigator 同样设定 fork_turns: "none",并在 prompt 里禁止它继续派生子 Agent,防止递归爆炸。
第 4 步:合并与验证
父 Agent 综合 auditor 和 investigator 的运行结果,根因相同、修复方式相同则合并为一个 finding,仅 CWE 相同不合并。
随后对每个 finding 进行一次源码路径检查,通过静态审计验证 finding 的真实性:
1 | attacker |
阶段四:验收与交付
Standard 完成审计后,Agent 将结果输出到 CODEX_SECURITY_SCAN_DIR 目录下:
1 | scan-manifest.json |
然后通过事件通知确定性代码验收:
1 | Codex turn.completed // Agent 运行结束 |
3. 全流程图
Standard 的流程全景如下:
graph TB
subgraph WA[确定性准备]
A1[CLI / SDK] --> A2[绑定目标与输出目录]
A2 --> A3[准备 Runtime 与 Plugin]
A3 --> A4[SQLite 注册扫描]
A4 --> A5[构造 Prompt]
end
subgraph WB[Agent 审计]
B1[Standard Preflight]
B2[Baseline Auditor]
B3[父 Agent 建立威胁地图]
B4[Focused Investigators]
B5[合并与源码验证]
B6[写入 Canonical JSON]
B1 --> B2
B1 --> B3
B3 --> B4
B2 --> B5
B4 --> B5
B5 --> B6
end
subgraph WA2[确定性交付]
C1[Python 生成 report.md]
C2[TypeScript 二次校验]
C3[SQLite 标记 complete]
C4[返回 ScanResult]
C1 --> C2 --> C3 --> C4
end
A5 --> B1
B6 --> C1
4. 设计要点
① 审查判断与状态发布分离
Agent 负责源码分析,但审计状态由确定性代码检查并更新,产物校验和数据库事务都成功之后,扫描状态才会转为 complete。
② Agent 写草稿,确定性代码负责定稿
Agent 先输出结构化的 JSON 结果,确定性程序再根据这些结果自动生成 report.md,而不是让 Agent 直接编写报告。
③ Baseline Auditor 与父 Agent 使用不同初始假设
baseline auditor 不接收父 Agent 生成的威胁假设,这种 prompt 隔离可以补充父 Agent 未覆盖的方向,降低漏报的概率。
