基于forgecode二开的agent cli
0

Configure Feed

Select the types of activity you want to include in your feed.

Rust 93.7%
Shell 3.2%
TypeScript 1.8%
HTML 0.9%
JavaScript 0.2%
CSS 0.1%
Nix 0.1%
Other 0.1%
2.9k 1 0

Clone this repository

https://tangled.org/c3n1g.tngl.sh/voge https://tangled.org/did:plc:jqd53ucf24u3nzl55f4fosyr
git@tangled.org:c3n1g.tngl.sh/voge git@tangled.org:did:plc:jqd53ucf24u3nzl55f4fosyr

For self-hosted knots, clone URLs may differ based on your setup.



README.md

🔎 Voge —— 多智能体漏洞挖掘流水线

基于污点追踪、完整性闸门与独立对抗式验证的盲测、系统化安全审计。

fork 自 tailcallhq/forgecode,从通用编码 agent 改造为漏洞挖掘引擎。


目录

Voge 是什么?#

Voge 是一条盲测漏洞挖掘流水线。把它指向一个源码树,它会像一位严谨的人类审计员那样审计代码的安全漏洞:枚举不可信输入的攻击面、把数据流追踪到每一个可达的危险 sink、逐一推理每一个净化器(sanitizer),然后用真实的 exploit 证明最强候选的成立——并且只有当独立的 agent 尝试反驳却失败后,才把一个发现标记为 confirmed

不是模式匹配器,也不是 CWE 关键词扫描器。发现靠的是语义化的污点追踪;最终产出是带可复现 PoC 支撑的、分级排序的发现报告。

它构建在 forgecode 的 agent 基础设施之上(provider 抽象、HTTP/工具调度、对话/记忆持久化、MCP、TUI 与 ZSH 插件),并用四个专门的安全 agent、一套污点图记忆系统以及一组机械化的完整性闸门替换了 forgecode 的通用编码 agent。

为什么需要单独的流水线?(它拦截了哪些失败模式)#

一个不受约束的 LLM「安全 agent」产出的报告,往往听起来很自信,却以特定的方式出错。Voge 的存在就是为了让这些失败模式在机制上无法被交付:

失败模式 Voge 如何阻止它
凭空捏造的发现(引用根本不存在、或没读过的代码) proof_of_read 反伪造:每条覆盖判定都必须引用一行从磁盘重新读取、且与所声明行号精确对应的源码行,并且该行对该文件必须是独特的(公共的 license 头/import 行会被拒绝)。
虚假的 confirmed(没有 exploit 却声称有) 确认闸门:除非独立的 adversary agent 记录了一条绑定到该发现安全实质(CWE + 严重程度 + 污点路径)的 survived 验证,否则 confirmed 会被机械地拒绝。
确认了中间 sink(效果在下游被中和) 记录的 sink 必须是权威执行闸门,而不是一个稍后被重新检查的中间值;adversary 必须把效果追踪到那里,并排除再执行(re-enforcement)。
「审计完成」但其实有文件从没打开过 覆盖完成闸门:除非 needs_review == 0partial == 0、每个 census 路径都有 safe/unsafe 判定、且 census 计数内部自洽,否则拒绝 finalize。
缩小的 census(只审了 25 个文件中的 2 个就声称完成) 每种语言一条「受认可、不可缩小」的 census 命令;闸门会用 agent 提供的路径列表交叉核对 census_total;只有 orchestrator 才能 finalize。
跨审计污染(同一仓库里的不同单元互相串台覆盖数据) 按 engagement 作用域化覆盖:每次运行由自动生成的 engagement_id 隔离。
一个不稳定的工具让一次 60 分钟的审计中止 gating 拒绝与「边路调查」工具(如 fetch)都被隔离出硬中止上限,各自有独立的后备上限。

工作原理 —— 四个 agent 的流水线#

        ┌────────────────────────────┐
        │  voge  (默认, task)        │   ← orchestrator + exploit 验证者
        └──┬──────────┬─────────┬────┘
  委派     │          │         │  委派
  侦察     ▼          │         │  验证
   ┌──────────────┐   │         │   ┌──────────────┐
   │  sage        │   │         │   │  adversary   │
   │  只读        │   │         │   │  独立        │
   │  污点追踪    │   │         │   │  反驳+重跑   │
   └──────────────┘   │         │   └──────────────┘
                     ▼
                ┌──────────────┐
                │  muse        │   ← 分级、排序、写报告
                └──────────────┘
Agent 角色 是否改文件?
voge Orchestrator + exploit 验证。构建并运行真实 PoC;唯一可以把发现标记为 confirmed 的 agent(且必须在 adversary 给出 survived 之后)。 是(写/运行 PoC)
sage 系统化攻击面枚举 + 污点追踪。只读侦察。
adversary 独立验证者:重新推导污点路径、寻找反驳性 guard、在未修改的目标上重跑 PoC。是 confirmed 的闸门。 仅 harness(绝不碰目标)
muse 分级、严重程度排序、撰写审计报告。 否(仅报告目录)

发现沿着 speculative → confirmed | refuted 的生命周期流转,记录在一个共享的污点图记忆里(memory_addmemory_update_findingmemory_find_taint_pathsmemory_coveragememory_verification 等)。完整 agent 指南见 docs/agents.md ——两条不可违背的规则(PoC 完整性、系统化审计)、验证闸门、发现生命周期,以及配置。

sink 是按语言区分的:内存安全语言(Go/Rust/Java)使用命令注入 / 路径穿越 / SSRF / 反序列化 / 资源耗尽 sink 以及文件传输元数据污点类;C/C++/unsafe-Rust/CGo 还额外有算术派生分配与溢出类。当出现 import "C" 时,CGo 对应的 .h/.c/.m 文件会被纳入 census。

完整性模型(真正防止错误结果的东西)#

  • 覆盖完成闸门memory_coverage_status(finalize=true))—— 一道代码闸门,而非文字检查。除非 needs_review == 0partial == 0total_latest == census_total、每个 census 路径都有 safe/unsafe 判定(drop-check)、且报告上盖的 coverage revision 与实时图一致(防漂移),否则拒绝 finalize。计数是按 census 作用域的,所以同一工作区里其他审计的覆盖不会阻塞——也不会虚假地满足——本闸门。
  • 确认闸门(绑定到安全实质) —— confirmed 要求一条 survived 验证,其记录的实质(CWE + 严重程度 + 污点 source/propagators/权威 sink/sanitizers)与发现精确匹配。「确认时拓宽」和「用窄祖先验证覆盖」这两种规避都会匹配失败。
  • 反伪造(proof_of_read —— 从磁盘重新读取被引用的行,并拒绝公共的 license/import 片段,所以一个从没打开过的文件的「safe」判定不可能通过。
  • engagement 作用域化 —— 覆盖与记忆按运行隔离;跨单元污染从结构上被消除。
  • 隔离的失败预算 —— gating 拒绝(gating_failure_limit)和边路调查工具(side_tool_names,如 fetch)各自在独立、更高的后备上限下计数,所以无论是闸门正常工作还是网络资源抖动,都不会让一次本可完成的审计中止。

快速开始 —— 跑一次盲测审计#

从源码构建(需要 PATH 上有 protoc):

export PROTOC="$(which protoc)"   # 或一个已知可用的 protoc 二进制
cargo build --release             # 产物:target/release/voge

配置一次 provider(兼容 OpenAI、Anthropic、OpenRouter 等):

voge provider login

对一个包跑盲测审计(headless 单次模式是主要用法):

# 审计一个 Go 包
voge -C /path/to/target -p "对 lib/services/ 下的 Go 代码做一次盲测安全审计。\
使用完整流水线:把枚举+污点追踪委派给 sage,用真实 PoC 验证最强候选\
(你是唯一可以确认的 agent,且必须在 adversary 记录 survived 之后),\
并把分级报告委派给 muse。跑到覆盖闸门 finalize 或明确的 escalation。"

审计报告默认写到本地 plans/ 目录(已加入 .gitignore,不会随仓库发布——里面含真实漏洞细节,请自行妥善保管)。

对于单次跑不完的大包,按子包拆分(每个分片有自己的 engagement):

scripts/voge_audit_split.sh /path/to/target lib/join 30

完整 agent 指南与配置参考见 docs/agents.mddocs/configuration.md

Voge 与上游 forgecode 的对比#

Voge 是 tailcallhq/forgecode 的一个 forkforge → voge 的重命名在历史里可见)。Forgecode 是一个通用 agentic 编码 CLI;Voge 保留了它的基础设施,把 agent 层改造用于安全审计。

forgecode(上游) voge(本 fork)
用途 通用编码 agent:解释、实现、重构、审查、提交 盲测安全漏洞审计
Agent 通用编码 agent 四个专门 agent:sage(侦察)/ voge(exploit+orchestrator)/ adversary(验证)/ muse(报告),星型拓扑
记忆 跨会话记忆存储 污点图记忆 + 覆盖追踪 + 绑定实质的验证
完整性闸门 覆盖完成闸门、对抗式确认闸门、proof_of_read 反伪造、engagement 作用域、边路工具/gating 隔离
发现方法 由 prompt 驱动 从不可信输入边界出发的、按语言的系统化污点追踪
主要模式 交互式 TUI / ZSH : 插件 Headless -p 盲测审计(TUI + ZSH 插件继承自上游)
产出 代码改动、提交信息 分级审计报告 + 可复现 PoC + 可查询的发现/污点图
共享 provider 抽象、HTTP 客户端、工具调度、对话持久化、MCP、Nix flake (原样继承)

如果你想要一个编码助手,用上游 forgecode。如果你想用一条「无法悄悄交付凭空捏造或未确认发现」的流水线来审计代码库的真实漏洞,用 voge。

继承自上游的能力#

这些来自 forgecode,行为与上游一致:

  • 三种运行模式 —— 交互式 TUI(voge)、单次 CLI(voge -p)、ZSH : 前缀插件(voge setup)。
  • 多 provider —— OpenAI、Anthropic、OpenRouter、Google Vertex、Bedrock、Groq,以及兼容 OpenAI 的端点(voge provider login)。
  • 对话持久化 —— 保存 / 恢复 / 克隆 / 分叉对话。
  • MCP —— .mcp.json server(项目级 + 全局)。
  • 自定义 agent / 命令 / skill —— .voge/agents/*.md.voge/commands/.voge/skills/
  • 语义搜索 —— :sync 给代码库建索引,支持按语义查找。

记忆系统 —— 跨审计隔离 + 跨会话学习#

Voge 的记忆不是「通用聊天历史」,是一个漏洞挖掘专用的污点图 + 覆盖追踪 + 验证历史,存于 ~/.voge/.voge.db(SQLite)。它让一个审计 run 的发现被持久化、可查询、跨会话累积,同时严格隔离不同审计/不同工程之间的覆盖与结论。下面是它怎么设计的、为什么这样设计。

记什么(按 kind 分类)#

kind 角色 生命周期
architecture 二进制/代码结构(包边界、sink 分布、调用层) 长期(很少变)
pattern 可复用的攻击模式(sink 类别、guard 模式、anti-pattern) 长期(cite-boost 加固,被 reinforce)
fact 客观事实(目标语言、工具能力、配置) 长期
bug / finding 候选漏洞(finding 带 taint source/propagator/sink + substance fingerprint) 活跃,被 supersede 推进
verification 独立验证结果(survived/refuted),绑定到 finding 的 substance 推动 finding → confirmed
coverage 已审计文件 + verdict (safe/unsafe/needs_review/partial) + proof_of_read 闸门级(count equality)
preference 用户偏好 长期

finding 的 substance fingerprint = hash(CWE + severity + taint source/propagators/sink/sanitized_by file_paths)——只 hash 安全实质,不 hash 文案。所以同一漏洞用不同措辞 filing 会被识别为同一 substance,验证不会跨文案漂移。

怎么隔离:engagement-scoped 一切#

engagement_id 是 voge 记忆的隔离基线(eng-<epoch_secs>-<pid> 格式)。所有 write path 自动盖戳(finding/coverage/verification 的 row 上),所有 read path 自动过滤(coverage/确认闸门等只读本 engagement 的行)。两条铁律:

  • engagement.id 显式 = 同 campaign 多审计共享(同一次活动的相关 audit 互相可见)。
  • 不设 = 每次 headless run 自动生成新 idrun_headless 在启动时设置 eng-<epoch_secs>-<pid>),完全隔离。这堵死了「同 workspace 多个审计互相污染覆盖与 verified 结论」。

engagement 字段在 ~/.voge/.voge.toml(或项目 .voge.toml)配;不配就隔离。配置示例见下面「与安全相关的配置」一节。

怎么版本化:supersede + is_latest 链#

每个 memory 有 id(UUID)+ fingerprint(hash(title, content))+ version + supersedes_id + is_latest。当一个 memory 被「修订」:

  • 旧 row 的 is_latest 置 0,保留(不删)。
  • 新 row 的 supersedes_id 指向旧 id,is_latest=1
  • 查询只看 is_latest=1;回溯用 supersedes_id 链。

好处:审计可被「修正」(finding 加新证据、coverage 从 needs_review 转 safe),但审计轨迹完整——你随时能看「这条 finding 是怎么从 speculative → confirmed 的」「这块代码是何时被审计的、当时发现了什么」。被 refute 的 finding 不删,留作「曾考虑过 + 为何驳回」。

save_memory 的去重——同 fingerprint 的 latest 存在则 update(不是 insert),配合 UNIQUE(project, fingerprint) WHERE is_latest=1 部分唯一索引 + upsert_memory 捕获 UniqueViolation 当 idempotent no-op——三重去重防并发竞态 + 同内容双写。

什么会强化 / 衰减(reinforcement / decay)#

memory_reinforcement(默认开):每条 memory 被引用时 usage_count++last_used_at 更新;非 finding 的 strength += 0.1finding 的 strength 是 0..1 的置信度,不被引用强化——置信度来自证据,不是引用次数)。

memory_decaystrength *= exp(-lambda * age_days),下限 min_strength(默认 0.1)。很久没人用的 fact/pattern 慢慢淡出,避免系统被陈年过时信息淹没;但 finding 不衰减(仍是可发现/可确认的)。

跨会话学习的工作方式#

一次 run 结束后,DB 留下三类长期资产:

  • pattern 记忆(如「libxml2 的 char-copy-loop 是 K 类 sink」):下次审计同语言/同类时,sage/voge 把它当强制规则对待。
  • architecture 记忆(如「SFTP 包 client-side vs server-side 的边界」):下次同项目再审计时直接复用。
  • fact 记忆(如「nsppe NS14.1.72.61 有 37840 函数、hexrays 可用」):下次扫同一二进制时直接 hit。

加上 supersede 链,长期演进的认知(v3 修了 v2 漏的 sink,v4 修了 v3 误报)都按 supersedes_id 串起来——你 cross-check 任意一条 finding 都能看到它的认知历史

怎么用#

memory_search / memory_read / memory_find_taint_paths / memory_coverage / memory_coverage_status / memory_update_finding / memory_verification——这些是 voge agent 的内存工具。系统 prompt 自动注入 top-N 摘要(按 strength 排序)到每轮对话,所以每个新 run 都从上次积累开始

~/.voge/.voge.db 可直接用 sqlite3 ~/.voge/.voge.db 查(Diesel 生成的 schema)——列出某 engagement 的 findings、查 substance fingerprint 重复、看 supersede 链。或者用 voge 自带工具:

voge memory search "q"       # BM25 搜 title/content/concepts
voge memory read <id>        # 单条
voge memory coverage         # 覆盖状态
voge memory taint-paths      # 查 taint 图

设计取舍(为什么不是别的样子)#

  • 不是「每个文件一份独立 DB」:会让 cross-file 关联(taint source/propagator/sink 跨文件、跨包)做不到;用单库 + engagement_id 隔离更简单。
  • 不是「按发现自动合并」:LLM-driven auto-consolidation(每 N 次 extraction 跑一次)会因 LLM 不稳定出错——所以 voge 的 substance_fingerprint + 闸门级 substance match 是机械的去重/确认,consolidation 是辅助的、LLM 决策失败也不污染基础。
  • 不是「无限增长」memory_decay + forget_expired(按 forget_after_days)+ superseded 链保留,保证 DB 不会无限膨胀。

具体配置(memory.auto_consolidate / consolidate_every_n_extractions / injection_summary / max_taint_depth / max_taint_paths)见 ~/.voge/.voge.toml。完整机制见 docs/configuration.mddocs/agents.md

与安全相关的配置#

~/voge/.voge.toml(或项目里的 .voge.toml):

# 对抗式确认闸门 —— 没有 survived 验证就拒绝 confirmed。
require_adversarial_verification = true

# 失败预算(相互隔离,所以正常工作的闸门或抖动的边路工具都不会让审计中止)。
max_tool_failure_per_turn = 3      # 核心工具
gating_failure_limit      = 8      # 闸门拒绝(隔离)
side_tool_failure_limit   = 12     # 边路调查工具(见下)
side_tool_names           = ["fetch"]

# engagement 作用域 —— 显式 id 把一组相关审计归到一个 campaign;
# 不设 => 每次运行自动生成一个新 id(完全隔离)。
[engagement]
# id = "my-campaign"
authorized_targets = ["lib/"]
out_of_scope       = ["vendor/"]

Headless 运行参数:VOGE_HEADLESS_STALL_SECS(流静默看门狗,不是总运行时长上限——总运行时长由你启动 voge 的外部包装,例如 timeout,来限定)。

局限与诚实的现状#

  • confirmed 在被独立追踪到权威执行闸门之前,只是一个候选。 adversary 被指示这样做,但这是 prompt 层面的;请把 voge 的 confirmed 当作「高置信度候选」,对任何你会据此行动的发现,自行复核其执行路径。
  • 需要完整运行时部署的漏洞(真实的网络/crypto/auth-server 栈)往往无法在沙箱里 PoC 确认,会停留在 speculative。纯逻辑漏洞(常见情况)通过单元测试 PoC 可以正常确认。
  • 非常大的单元可能超出单次运行的预算——用 scripts/voge_audit_split.sh 按子包拆分。
  • 这是一个研究/评估工具,不是一个被支持的产品。每个目标的评估往往都会暴露并修复另一个流水线缺口。

致谢与许可#

Voge fork 自 tailcallhq/forgecode。其 agent 基础设施(provider、HTTP、工具、对话/记忆持久化、TUI、ZSH 插件、MCP)属于 forgecode;漏洞挖掘 agent、污点图记忆与完整性闸门是本 fork 的工作。许可条款见 LICENSE