它是什么
DSH Pentest 安装的是一个渗透测试 agent 预设(渗透模式):在授权范围内记录目标、探索线索、已验证的结果、资产与漏洞,并在 Web 界面中展示这些内容。仓库 owner 是 GitHub 用户 howmp,仓库描述末尾带 @CloverSecLabs;除此之外没有任何 LICENSE、NOTICE 或 README 说明这种关系的性质。
最关键的一点是:能力到底长在哪里。 这个包注册的是台账类工具、一个系统提示词段、一个会话投影。它内部没有 HTTP 客户端、没有 socket、也没有进程孵化能力——在发布出的 lib/pentest.js 里检索 fetch(、http.request、net.connect、child_process、execSync、spawn(,每一项命中数都是 0。真正打到目标上的请求来自 shell,而 shell 之所以在这个预设里,是因为预设授予了它,不是因为本插件提供了它。
所以它不是「指向一台主机就能扫」的扫描器,而是给 agent 已有的能力配一层记录与可视化。
探索链路
按 src/dsh-pentest/src/spec.ts:一个会话持有唯一一个 goal(target、objective,可选 authorization)。intent 锚定到 goal(spawns 边)或某个 fact(derived_from);intent yields fact,fact 可推导出新的 intent,intent proves finding。finding 必须带至少一条 reproducibleSteps,存储层强制这一条。资产(root-domain、subdomain、ip、service、app、endpoint)通过 parent 边挂接。边的种类是封闭的五个:spawns、yields、derived_from、proves、parent。
节点与边的 id 是确定性的(<kind>-<n>,按会话计数),Web 视图因此可以靠重放已记录的 pentest_* 调用重建同一张图,而不必读数据库。
九个工具,以及谁可以调用
包 README 的表格列了八个:pentest_add_goal、pentest_add_intent、pentest_add_fact、pentest_add_finding、pentest_add_asset、pentest_state、pentest_graph、pentest_report。正文却说「九个面向模型的工具」;第九个是 pentest_submit,只对子 agent 开放。
调用权是分置的,不是共享的。决策 agent(根 agent)拥有那八个记录与读取工具。预设的委派行带一份显式 toolFilter,把上述八个连同 subagent、subagent_fork 一起 deny 给执行子 agent,只留给它们 pentest_submit——该工具从委派关系反推父会话。
两个实际后果。pentest_add_goal 是破坏性的:它清空该会话的 intents、facts、findings、assets、edges,并把 id 计数从 <kind>-1 重新开始;仓库自己的 docs/goal-reset.md 称其为「一项特权破坏性操作」。另外 pentest_submit 拒绝占位符 intent id,委派必须带上 pentest_add_intent 刚返回的真实 id。
预设实际授予了什么
preset/pentest/agent.cordis.yml 按它自己的头注释,是「对内置 standard 预设的一份拷贝,只加了一行——@deepseek-ai/dsh-pentest——外加一个指挥官人格」。行清单证实了这一点:shell(tool-bash、tool-pwsh)、文件系统与检索、jobs、skills、goals、planning、compaction、四个 subagent 行、workflow、ralph、ask_user_question、todo、web,全部原样继承。
这份清单就是「这个 agent 会做什么」的答案。因为 shell 行在里面,agent 本体——以及继承父组合的执行子 agent——可以执行命令,而打到目标上的正是这些命令。插件贡献的是纪律与台账,shell 贡献的是触达能力。
指挥官人格很简短:它负责决策与创建 intent,提案生成与执行都委派出去。真正的协议文本以 pentest:protocol 系统提示词段(order 50)注入,用中文写成,包括「与用户的所有交互一律使用中文」这条。其中一行写着范围规则:任何偏离 pentest_state 所记录授权范围的意图都应被拒绝。
授权是「记录」,不是「闸门」
README 说得很直白,源码也一致:goal 的 authorization 字段是一条声明性备注(授权方或书面许可引用),「作为可审计事实记录,不是门禁:执行仍归部署侧的沙箱/审批层。」
代码里没有目标白名单、没有域名匹配、没有任何范围校验。包 README 的限制清单也是同一句话——「本包自身不拦截工具;沙箱/审批配置仍属部署方的责任。」协议提示词确实要求决策 agent 拒绝越界意图,但提示词指令不是机制,而且没有任何东西会验证那条授权备注是否真实。
授权字段留下的是审计痕迹,它拦不住任何东西。 真正的约束来自你的 DSH 部署为 shell 执行已经配置的沙箱与审批设置。
数据落在哪、存了什么
本包声明了一个存储域 pentest(version 2),含六张表:goals、intents、facts、findings、assets、edges。bundle 里的 cordis.patch.yml 装了一个 sqlite 后端,路径为 dshHomePath('storages', 'pentest-sessions.db')——实际即 $DSH_HOME/storages/pentest-sessions.db——并只把 pentest 这一个域路由到它;其它域沿用宿主的 json 后端。记录以 sessionId:id 为键,因此一次 engagement 被限制在单个会话内。
**关于凭据:**没有凭据表,六张表的 schema 里也没有任何凭据字段。fact 带 kind、target、detail、confidence;asset 带 type、value 和自由文本 meta。需要留意的是 detail 与 meta——两者都是 agent 写入的自由文本,所以密码或 token 有可能被 agent 写进去。schema 既不提供存放密钥的字段,也不阻止这件事。
装的是构建产物
上游命令安装的是 Release tarball,不是源码检出,也不是 npm 包。@howmp/dsh-pentest 不在 npm 上——registry 对带 scope 的名字和 dsh-pentest 都返回 404——所以本条用 install: 而不是 package:。
当前最新 release 是 v0.1.0-rc.30(2026-09-11),其唯一资产 dsh-pentest.tar.gz 为 216,652 字节。releases/latest/download/… 这个 URL 可用:经两次跳转后返回 HTTP 200,下载字节数一致,SHA-256(6ad06af1…4763)与 GitHub 报告的资产摘要吻合。
tarball 共 14 个文件,不含源码。 里面有 package.json、cordis.patch.yml、README.md、lib/ 下八个编译后的 JavaScript 文件(含 608 KB 的 lib/pentest.js 与 486 KB 的 lib/ui-pentest.client.js)以及两个 preset/pentest/ YAML——没有 src/、没有测试、没有 .ts、没有 source map。仓库里确实有一份可读的 TypeScript 快照(src/dsh-pentest/src/ 与 src/dsh-client-ui-pentest/src/),但没有任何东西把实际加载的字节与它绑定;要对照只能手工 diff 或本地重新构建。
安装期不执行任何代码。 发布出的 scripts 只有一项 "test": "vitest run"——没有 preinstall、install、postinstall、prepare、prepublish、prepack。Release 工作流只在打版本 tag 时运行:npm ci --legacy-peer-deps && npm test,然后 npm pack,再重命名为 dsh-pentest.tar.gz。
运行要求
- Node.js >= 22.5:sqlite 后端用的是内置
node:sqlite(见docs/storage.md)。 - Harness
0.1.0-rc.6是作者声明的目标。AGENTS.md写着 “The bundle targets DSH0.1.0-rc.6; align peer dependencies and rebuild from the matching upstream version when DSH APIs change”,发布出的清单也照此钉死——dsh-invariants、dsh-storage、dsh-storage-domain、dsh-tools都恰为0.1.0-rc.6(@deepseek-ai/cordis为^4.0.1)。根 README 用简写指同一个版本(“compatible with DSH rc.6”)。清单里没有dsh.compatibility或dsh.target块,所以这些 peer 钉版是安装要求,不是兼容承诺。另外 persona 行同时带prefix(0.1.3起必需)与旧版text别名(0.1.2及以前必需),让同一份预设能在两条线上挂载——这是兼容手法,不是「测过哪些版本」的声明。 - **依赖:**运行时为
zod与@deepseek-ai/schemastery。客户端半边注入dsh-client-runtime、dsh-client-locale、dsh-client-ui-conversation,平台声明为web——它不是为 headless 或纯 CLI 形态做的。 - **遥测:**未发现。对 tarball 内全部文件检索
telemetry、analytics、sentry、posthog、mixpanel、umami均无命中,插件自身也不发起任何外部调用。README 对此没有说明。README 同样没有为预设授予的 shell 记录任何权限模型。
已知限制
- 完全没有任何范围强制机制。
- 仓库里没有许可证文件。 发布出的
package.json声明"license": "MIT",嵌套的宿主包同样声明 MIT,但仓库里没有LICENSE、LICENSE.md、COPYING或NOTICE——GitHub 的 license API 返回 404,社区档案里"license": null。请把它当作一条没有附件的声明:在没有许可证正文的情况下,等于未正式声明许可证,默认保留所有权利。 本条记录清单里的取值,因为那是仓库对自己的陈述,它不是授权存在的独立证据。 - Web 标签页在没有挂载证据时会隐藏自己。
pentestMounted单元只有在该会话自身日志证明组合挂载了本包时才置真——组装出的工具 schema 里出现pentest_*、存在已记录调用、或折叠出委派提交。原因是预设无法从浏览器读取,所以复制出来的预设靠日志证据识别,而不是靠名字。 - 图是窗口视图——会话投影各保留最新 200 个节点、资产与边,最旧的被逐出;完整记录在
pentest_state与pentest_report之后。布局是静态分层的:可平移缩放,节点不可拖拽。 - 一会话一 goal。 没有跨会话续跑;重新开始一次 engagement 需要新的
pentest_add_goal,会丢弃该会话此前的链路。 - 转录由 agent 负责。 README 明确写「没有任何东西校验转录是否完整或忠实」;同一会话内多 agent 并发写也不会在每域队列之外额外串行化。
什么时候用它、什么时候不要用
当你在做一次已获授权的测试,并且希望 agent 的发现最终沉淀成一张可查询的图——带父子关系的资产、每条都附可复现步骤的漏洞、可重新生成的报告——而不是散落在长对话里的散文,就用它。reproducibleSteps 是存储层强制的最有用的一条规则:它让「我觉得这里有洞」写不进去,只有「这样复现」才落得下来。
不要指望它是扫描器,也不要把授权字段当成保险。它自身不扫描任何东西,也不会阻止 agent 对一台从未在范围内的主机执行命令——那条边界属于你的沙箱配置,也属于你。另外,如果你打算再分发或基于它构建,请注意许可证文件缺失这件事。
FAQ
这个插件会自己去攻击目标吗?
不会。它注册九个 pentest_* 台账工具、一个系统提示词段和一个会话投影——没有 HTTP 客户端、socket 或进程孵化能力,这些检索在发布出的 lib/pentest.js 里命中数都是 0。真正触达目标的是预设授予的 shell,执行子 agent 会继承它。插件负责记录,shell 负责动手。
它会强制授权范围吗?
不会。goal 上那个可选 authorization 字符串,源码自己描述为「可审计事实,不是门禁」,包 README 也确认「本包自身不拦截工具」。代码里没有白名单或范围校验。协议提示词确实要求决策 agent 拒绝越界意图,但那是对模型的指令,不是控制手段。
数据库会存凭据吗?
没有专门字段。pentest 域那六张表都没有凭据、密码或 token 字段。但 facts.detail 与 assets.meta 是 agent 写入的自由文本,secret 有可能被写进去。文件是 $DSH_HOME/storages/pentest-sessions.db;其它存储域仍走宿主的 json 后端。
为什么安装命令指向 Release tarball 而不是 npm?
因为这个包不在 npm 上——registry 对 @howmp/dsh-pentest 和 dsh-pentest 都返回 404,package: 无从解析。tarball 里是 14 个编译产物、没有源码,所以你装的是构建产物;仓库里有一份 TypeScript 快照可以对照,但两者之间没有自动关联。安装过程不执行代码。
它面向哪个 harness 版本?
AGENTS.md 声明 DSH 0.1.0-rc.6,发布清单把 dsh-invariants、dsh-storage、dsh-storage-domain、dsh-tools 都钉在恰为该版本。根 README 用简写说同一件事(“DSH rc.6”)。清单里没有 dsh.compatibility 块,所以那些 peer 钉版是安装要求而非兼容承诺,也没有任何来源说明实际测试过哪些版本。