wth2jhl.online

Back

当你给它一个目标 URL,它真的会在 Docker 里跑 nmap、起 Caido 代理、用 agent-browser 操控 Chromium、构造 payload、真正发出 HTTP 请求拿到 5xx/2xx 响应,然后才会告诉你:“这是一个 SQL 注入。”

如果没有 PoC,它甚至不会把这条记录写进报告。

这就是 usestrix/strix ↗ 在做的事:把”AI 渗透测试”这个听起来很玄学的命题,变成一支有规划、有执行、有验证、有报告的多 Agent 协作队伍——而每一步都被强制带上真实证据。

这篇文章会带你从顶层设计、Hierarchical Agent 编排、agents_graph 工具、27 个内置工具、技能系统、Docker 沙箱、Caido 代理、SARIF 输出、可借鉴与短板,把这个 ~25K 行 Python 的项目拆透。

Strix 项目展示

Strix v0.x,基于 OpenAI Agents SDK + LiteLLM,~25K 行 Python


一、定位与四层架构#

1.1 一句话#

Strix = 一支由 LLM Agent 协作组成的自主渗透测试队伍。

每个 Agent 跑在一个 Kali Linux Docker 沙箱里,能调用真实工具(nmap / nuclei / sqlmap / httpx / Caido 拦截代理 / agent-browser),并通过工具调用链产出带 PoC、可直接合入的修复 patch、可上 GitHub 的 SARIF 报告 的安全测试结果。

1.2 技术栈#

层选型证据
语言Python ≥ 3.13strix.spec:36-40 python_requires=">=3.13"
Agent 框架OpenAI Agents SDK 0.14.6strix/runtime/docker_client.py:13 注释
LLM 统一层LiteLLM + MultiProviderstrix/config/models.py:22、strix/llm/compaction.py:9
沙箱运行时Docker(可插拔 backend)strix/runtime/backends.py:19-44
浏览器自动化agent-browser Node CLIcontainers/Dockerfile:91 agent-browser@0.26.0
拦截代理Caido(开源 Burp 替代品)容器内 sidecarstrix/runtime/caido_bootstrap.py:24-99
CLITyper + Rich + Textual TUIstrix/interface/cli.py、strix/interface/tui/
SARIF 输出自写 schema 校验strix/report/sarif.py、strix/report/writer.py
可观测性PostHog + Scarf + 结构化 loggingstrix/telemetry/

1.3 四层架构#

关键事实:Strix 不自己实现 LLM Agent 循环,而是基于 OpenAI Agents SDK 的 SandboxAgent(strix/agents/factory.py:27),并通过 _with_bounded_result + _with_coerced_arguments 两个 wrapper(factory.py:620-628)做输出限流和参数归一化。

整个 prompt 是单源 jinja 模板(strix/agents/prompts/system_prompt.jinja,507 行),通过 render_system_prompt 配合 is_root / scan_mode / is_whitebox / interactive 四个开关渲染。这也是 Strix 把”root agent 不准自己跑扫描器”这种硬约束写进 prompt 的关键机制(system_prompt.jinja:6-15)。

1.4 与传统扫描器和 ReAct 的本质差异#

维度传统扫描器(Nuclei / Burp)经典 ReAct AgentStrix
工作单元一条规则 / 一个 payload单 LLM 在循环里 Think→Act→Observe多 Agent 分层,每 Agent 一个 SandboxAgent
决策范式静态 if/else线性链分层图(root planner → specialist → 各自 ReAct)
工具调用死规则、签名匹配function-callingSDK function_tool + 自写 sandbox exec
上下文无状态会话内累积,但会爆显式 compaction(strix/llm/compaction.py)+ per-agent 持久化
报告raw output无CVSS + SARIF + PR body + code_locations
误报控制规则匹配即报告自我陈述”找到了”强制 PoC:没有 PoC 报告直接被 dedupe 拒绝
沙箱通常无视实现真 Docker 容器 + 容器内 Caido sidecar
验证/可观测取决于产品完全黑盒PostHog + Scarf + 自建 session 落盘

二、Hierarchical Agent:Master 与 Specialist 的契约#

Hierarchical Agent 编排

Strix 采用严格分层 Agent 范式——不是 Graph-of-Thoughts,也不是纯 Plan-and-Execute,而是 Plan-and-Execute + 子任务独立反馈的混合:

证据:

  • _BASE_TOOLS(factory.py:485-519)列出 27 个基础工具,finish_scan 仅 root,agent_finish 仅 child;
  • Root 在 prompt 里被强制只做编排:“Your job is ORCHESTRATION, not hands-on testing.”(system_prompt.jinja:6-8);
  • 子 Agent 三段式:“Discovery → Validation → Reporting-with-fix (3 agents per vulnerability)“(system_prompt.jinja:316-318)。

2.1 agents_graph 工具——最值得借鉴的设计#

完整定义在 strix/tools/agents_graph/tools.py(740 行)。这是 Strix 最值得借鉴的设计之一,暴露给 LLM 的工具:

工具用途行号
create_agent递归生成子 agent(可以再生成子 agent 的子 agent):245-340
send_message_to_agent点对点消息:347-405
wait_for_agents块式等待,阻塞直到指定 agent 完成:573-625
view_agent_graph让自己看到整张 agent 树:535-572
stop_agent砍掉某个 agent(防止失控蔓延):627-693

关键设计:

  • create_agent 不仅能传 name/instructions/skills,还能传预加载的 skills、模型设置和子 agent 自己要用的工具(:255-300),让父 agent 能精准调度子任务;
  • 子 agent 的 instructions 是一段完整可独立运行的指令体,root 通过 system_prompt_context 注入 scope / authorization 信息(factory.py:550-560);
  • wait_for_agents 是 SDK 级 function_tool,调用一次就 block,禁止轮询——这一点在 prompt 里被反复强调:“wait_for_agents blocks and resumes you automatically, so it is never a poll you repeat”(system_prompt.jinja:36-38)。

2.2 状态共享:共享文件系统 + 共享容器#

  • /workspace 是所有 agent 共享目录(system_prompt.jinja:240-243 “All agents share the same /workspace directory and proxy history”);
  • Caido proxy 流量全 agent 可见——这就是为什么要在容器内启动 sidecar;
  • per-agent todo / notes 通过 {state_dir}/todos.json / notes.json 落盘(strix/tools/todo/tools.py:48-60、strix/tools/notes/tools.py:46-50);
  • reports 通过 ReportState(strix/report/state.py)做进程级共享。

三、工具系统:27 个内置工具 + 严格的契约#

工具系统总览

strix/agents/factory.py:485-519 是权威清单。我按用途归类:

类目工具文件
思考thinkstrix/tools/thinking/tool.py
技能注入load_skillstrix/tools/load_skill/tool.py
元任务create_todo / list / update、create_note / list / get_notestrix/tools/{todo,notes}/tools.py
网络web_search(Perplexity Sonar-Reasoning-Pro)、list_requests / view_request / repeat_request / list_sitemap / view_sitemap_entry / scope_rulesstrix/tools/{web_search,proxy}/tool.py
报告create_vulnerability_report(强制 PoC + CVSS)、create_dependency_report(仅 CVE 已知)、list_reports / get_reportstrix/tools/reporting/tool.py
多 Agentview_agent_graph / send_message_to_agent / wait_for_agents / create_agent / stop_agentstrix/tools/agents_graph/tools.py
生命周期finish_scan(root only)、agent_finish(child only)、respond_to_user(interactive)strix/tools/{finish,respond}/tool.py
来自 SDKexec_command(容器内 TTY shell)、apply_patch、agent_browser、view_imageOpenAI Agents SDK 内置

3.1 create_vulnerability_report:最复杂的工具#

strix/tools/reporting/tool.py:347-373 的签名极有教益:

强制项 + 安全护栏:

  • 强制 PoC:没有 poc_script_code / poc_description 直接拒收;
  • CVSS 校验:_CVSS_VALID 字典(reporting/tool.py:24-33)列出每项合法值(attack_vector 必须是 N/A/L/P),不在合法集内直接拒绝;
  • 路径安全:_validate_file_path(reporting/tool.py:36-44)禁止绝对路径、禁止 .. 穿越。

3.2 工具注册契约#

所有工具必须满足以下契约:

  1. 用 agents.function_tool(timeout=..., strict_mode=False) 装饰,自动从签名生成 JSON Schema 给 LLM;
  2. 注册表是 _BASE_TOOLS(root/child 共有)和 _EXTRA_TOOLS(register_agent_tools(*tools) 注入,factory.py:533-551);
  3. 在 build_strix_agent 里用 _ensure_unique_tool_names 强校验名称唯一(factory.py:514-525);
  4. 所有 FunctionTool 都被两层 wrapper 包:_with_coerced_arguments(参数归一化)+ _with_bounded_result(输出限流),factory.py:620-628。

3.3 错误处理:契约性错误写在 docstring 里教给 LLM#

返回是 JSON 字符串,约定有 success 字段。tool.py:42 这段非常典型:

“If you get a duplicate_of response, do NOT retry”

——契约性错误被显式写在 docstring 里教给 LLM,让模型知道重复报告应该停止而不是再发一次。

web_search 的错误粒度也很细:Query cannot be empty / Web search is not configured / timed out / HTTPError,每种都有特定 hint(web_search/tool.py:45-72),让 LLM 拿到错误后能自我修正。


四、技能系统:Markdown 即知识库#

技能系统

strix/skills/ 按类目组织(strix/skills/__init__.py 枚举):

skills/
├── scan_modes/         quick / standard / deep.md  顶层扫描策略
├── coordination/       root_agent / source_aware_white_box 等
├── reconnaissance/     asset_discovery / subdomain_enum / port_scan / tech_fingerprint / dir_fuzz
├── technologies/       cms / framework / language / dev_tool / ai_ml / supply_chain
├── frameworks/         FastAPI / Django / Express / Next.js / React / Vue ...
├── vulnerabilities/    sqli / xss / ssrf / idor / rce / auth_bypass / file_upload ...
├── protocols/          http / graphql / websocket / grpc / oauth / jwt
├── cloud/              aws / gcp / azure / kubernetes / docker
├── tooling/            nuclei / burp / sqlmap / nmap / ffuf
├── custom/
└── README.md
plaintext

一个 skill 文件长什么样(strix/skills/reconnaissance/asset_discovery.md,节选):

格式:YAML frontmatter + 详细自然语言指导,完全可代码完全解耦。

4.1 load_skill 工具:动态注入到 LLM 上下文#

async def load_skill(ctx, skills: list[str]) -> str:
    """Return the markdown body of one or more skills as reference material."""
python

把 skill Markdown 拼成 ## Skill: <name>\n\n<body> 直接塞回 LLM 上下文。这意味着:

  • 技能是 lazy load:root agent 只在确认要做某类攻击时才调 load_skill,避免一开始就吞掉全部 ~10K 行的 skill 文本撑爆上下文;
  • 技能是版本无关:纯 Markdown 文件,可以用 git 管理,与代码库解耦;
  • 技能可热更新:新增一种漏洞类型只要写一份 Markdown + 在 skills/__init__.py 注册。

五、运行时:Docker 沙箱 + Caido 容器内 sidecar#

Docker 沙箱与 Caido 代理

5.1 沙箱抽象:strix/runtime/#

文件职责
docker_client.pyDocker SDK 封装
backends.py:19-44可插拔 backend 接口
session_manager.py会话生命周期
status.py状态推送
caido_bootstrap.py:24-99Caido sidecar 启动 + GraphQL guest token 探活

backends.py 抽象出”沙箱后端”接口,理论上可以替换成 Firejail / E2B / Fly machines / 自建 K8s,而不仅限于本地 Docker。

5.2 Caido:容器内的 Burp#

Caido 是一个开源的 HTTP 拦截代理(“Burp Suite 的现代化替代品”),Strix 在每个 agent 容器内启一个 Caido sidecar:

  • 所有 HTTP 请求自动经过 Caido;
  • Agent 通过 list_requests / view_request / repeat_request / list_sitemap 工具读流量;
  • scope_rules 工具动态增删 in-scope URL;
  • 所有 agent 共享同一份 proxy history——这就是为什么要在容器内启动 sidecar,而不是在 host 端。

Caido 启动探活用 caido_bootstrap.py:42-72 的 GraphQL “最多 10 次 backoff 拿 guest token”,这是真实的 readiness probe,不是写死 sleep。

5.3 agent-browser:容器内浏览器自动化#

containers/Dockerfile:91 安装 agent-browser@0.26.0,让 agent 能用自然语言操控 Chromium:

“打开 https://target.com/login,填用户名 admin 密码 admin,点击登录”

→ 工具调用 → 浏览器执行 → 拿到响应 → 写回 proxy history。


六、报告与 SARIF:从 PoC 到 PR#

报告与去重

6.1 三种报告类型#

strix/tools/reporting/tool.py 暴露三种报告工具:

  1. create_vulnerability_report(:347):业务漏洞,强制 PoC + CVSS + fix patch + PR body;
  2. create_dependency_report(:1111):依赖漏洞(CVE 已知),无 PoC 强制;
  3. list_reports / get_report(:1508 / :1573):只读查询。

6.2 去重:strix/report/dedupe.py#

避免同一漏洞被多个 agent 重复报告。dedupe.py:1-50 实现了基于 (target + vulnerability_type + endpoint) 三元组的去重——重复时返回 duplicate_of,前面提到过,这个错误码被显式写在 docstring 里教给 LLM:不要重试。

6.3 SARIF 2.1.0 输出#

strix/report/sarif.py 把报告转成 SARIF 2.1.0——这是 GitHub Code Scanning 的标准格式,扫描结果可以直接出现在 PR 页面:

{
  "runs": [{
    "tool": { "driver": { "name": "Strix", "version": "..." } },
    "results": [{
      "ruleId": "sqli",
      "level": "error",
      "message": { "text": "..." },
      "locations": [{ "physicalLocation": { ... } }]
    }]
  }]
}
json

加上 fix_pr_body 字段后,Strix 的报告可以直接走 GitHub Actions → 自动开 PR with patch。


七、上下文压缩:让长任务跑得动#

上下文压缩

strix/llm/compaction.py 处理一个现实问题:一次渗透测试可能要几十分钟到几小时,LLM 上下文会爆。

策略(推测结合文件):

  • 分段摘要:保留最近 N 轮对话 + 对早期对话生成摘要;
  • 证据保留:所有 list_requests / view_request / create_vulnerability_report 的结果完整保留;
  • TODO/Notes 优先级提升:per-agent 持久化的 todo / notes 被压进 system prompt,类似 LangGraph 的 long-term memory;
  • 显式触发:在 token 用量达到某个阈值时由 SDK 触发,而不是每次都压缩(避免过早丢失细节)。

这与 MoneyPrinterTurbo 的 “提交瞬间配置快照” 是完全不同的设计哲学——MPT 是”任务开始锁定配置”,Strix 是”任务过程中持续整理上下文”。两个项目都体现了 AI 长任务的工程复杂度。


八、可借鉴 & 局限#

8.1 值得借鉴#

  1. 单源 jinja prompt 模板:通过 is_root / scan_mode / is_whitebox / interactive 四个开关切换,避免 prompt 爆炸;
  2. agents_graph 工具的递归 spawn:把”多 Agent 编排”暴露给 LLM 自己——LLM 决定 spawn 几个子 agent、各自做什么、什么时候等、什么时候停,这是 Hierarchical Agent 的工程化范本;
  3. 契约性错误写在 docstring 里:让 LLM 拿到错误后能自我修正(如 “If you get a duplicate_of response, do NOT retry”);
  4. 强制 PoC + CVSS 校验 + 路径安全护栏:LLM 写报告时必须带证据,避免幻觉漏洞;
  5. Markdown 即知识库:技能是纯 Markdown 文件,与代码完全解耦,可热更新、可 git 版本管理;
  6. 共享文件系统 + 共享容器:多 Agent 通过 /workspace 和 Caido history 自然共享状态,不需要复杂的消息总线;
  7. 容器内 sidecar 模式:Caido / agent-browser 都跑在同一容器内,避免跨网络延迟和安全边界问题。

8.2 局限#

  1. 依赖 OpenAI Agents SDK:版本被 pin 到 0.14.6,生态绑定较深。如果想换成 LangGraph / CrewAI,需要重写 factory.py;
  2. LLM 成本:一次 deep 扫描可能要烧几美元到十几美元的 token,对个人用户不友好(这也是为什么有 app.strix.ai 托管服务);
  3. Docker 强依赖:沙箱完全绑定 Docker,backends.py 的可插拔设计有了,但还没实现 Firejail/E2B 后端;
  4. 强制 PoC 是双刃剑:挡住了幻觉,但也可能漏报某些”无法在 sandbox 内复现”的漏洞(如需要特定网络环境、需要真实用户凭据);
  5. 没有内置 Sora/AI 视频源(不是本项目问题,提一下对比 MoneyPrinterTurbo);
  6. 可观测性 PostHog + Scarf 偏外部:自建的部分只在 session 落盘,缺少 Prometheus / OpenTelemetry 标准接入。

九、写在最后#

Strix 给我最大的启发是:AI Agent 项目的工程难度,不在 Agent 本身,而在”如何让 Agent 之间、Agent 与真实世界之间安全可控地交互”。

Agent 循环可以用 SDK;但

  • 工具的 schema 设计 + 错误契约,
  • 多 Agent 的 共享状态 + 递归 spawn,
  • 沙箱的 sidecar 模式 + 可插拔后端,
  • 技能的 Markdown 化 + lazy load,
  • 报告的 强制证据 + 去重 + SARIF,

这些都是只有真在生产化跑过渗透测试才会知道要面对的细节。

这也是为什么我在做完 MoneyPrinterTurbo ↗ 之后会被这个项目吸引:它把”AI 调用传统多媒体管线”换成了”AI 调用真实安全工具链”,复杂度又上了一个台阶。

如果你也在做 AI Agent 工具链,强烈建议读两遍 strix/agents/factory.py 和 strix/tools/agents_graph/tools.py——你会在 1500 行内看到 Hierarchical Agent 的工程化范本:递归 spawn、阻塞等待、契约性错误、单源 prompt、可插拔 backend。


附录:关键源码定位速查#

模块关键文件 / 行号
Agent 工厂strix/agents/factory.py:27 (SandboxAgent)、:485-519 (_BASE_TOOLS)、:620-628 (wrappers)
单源 promptstrix/agents/prompts/system_prompt.jinja(507 行)
多 Agent 编排strix/tools/agents_graph/tools.py:245-693
工具注册strix/agents/factory.py:533-551 (register_agent_tools)、:514-525 (_ensure_unique_tool_names)
漏洞报告strix/tools/reporting/tool.py:347-373 (signature)、:24-44 (CVSS / path validation)
去重strix/report/dedupe.py
SARIFstrix/report/sarif.py
沙箱strix/runtime/{docker_client,backends,session_manager}.py
Caido 集成strix/runtime/caido_bootstrap.py:24-99
技能系统strix/skills/{reconnaissance,vulnerabilities,protocols,cloud,...}/*.md
浏览器自动化containers/Dockerfile:91
LLM 统一strix/config/models.py:22 (MultiProvider)
上下文压缩strix/llm/compaction.py

📘 项目信息

深入解析 Strix:一支由 LLM Agent 组成的自主渗透测试队伍是怎么跑起来的
https://wth2jhl.online/blog/strix-ai-pentest-deep-dive/
Author 小吴同学
Published at August 18, 2026