本文是本栏第2轮的单件深拆,对象选了安全赛道上一个很少被翻牌子的组合:security-threat-model 及其同门 security-best-practices、security-ownership-map。三件共享同一个 security- 前缀,各管一段:一件负责给代码仓库「开庭定罪」式威胁建模,一件负责按语言框架写出带安全默认值的代码,一件负责从 git 历史里考古出所有权风险。主菜是第一件——它的 SKILL.md 是近年少见把「证据链、暂停点、反灌水、自检」四种纪律同时写进流程的范本,拆到每一段,你能看到一份提示词是如何长得像一份司法程序的。文中全部引用均出自三份 SKILL.md 原文,评分为文本评析,未经长期实测佐证处会注明。
| 技能 | 一句话定位 | 核心产出 |
|---|---|---|
| security-threat-model | 对指定仓库做 AppSec 级威胁建模 | <仓库名>-threat-model.md 报告 |
| security-best-practices | 识别技术栈后按参考文档写安全代码 | 安全报告 security_best_practices_report.md 与修复 |
| security-ownership-map | 从 git 历史算所有权与共变风险 | people/files/edges 三张 CSV 加 summary.json |
三件不是重复造轮子,而是按「论证层—写码层—历史层」分工:一件管审前取证,一件管判后改判,一件管翻旧账。这个分层本身就是值得抄的设计——与其做一件什么都管的大而全,不如让三件在名字前缀上结拜,各自只把一段流程写透。
flowchart TD
FAM["security 安全位三件套"] --> TM["threat-model 威胁建模"]
FAM --> BP["best-practices 按栈写安全码"]
FAM --> OM["ownership-map git历史考古"]
TM --> R1["产出 威胁模型报告"]
BP --> R2["产出 安全报告与修复"]
OM --> R3["产出 所有权风险清单"]
| 维度(权重) | threat-model | best-practices | ownership-map |
|---|---|---|---|
| 功能完整度 25% | ★★★★ | ★★★☆ | ★★★★ |
| 设计质量 25% | ★★★★★ | ★★★★ | ★★★★ |
| 实战效果 20% | ★★★★ | ★★★ | ★★★☆ |
| 上手难度 15% | ★★★★★ | ★★★★★ | ★★★ |
| 社区活跃度 15% | 未核验 | 未核验 | 未核验 |
| 综合(前四维) | ★★★★☆ | ★★★☆ | ★★★☆ |
说明:三件均为本地可读的 SKILL.md 原文评析,star 数与下载量本轮未获独立来源核验,社区维度留空,不编数字。实战效果按流程完备度与失败路径处理推演给分,保守处会低于观感。
SKILL.md 正文第一句就亮立场:
Deliver an actionable AppSec-grade threat model that is specific to the repository or a project path, not a generic checklist.
「不是通用清单」这半句是整份文件的宪法。威胁建模这类任务,模型最擅长的偷懒方式就是背一段 OWASP 十条交差。这句宣言把交差路径直接封掉,紧接着补了一句更狠的:
Anchor every architectural claim to evidence in the repo and keep assumptions explicit.
每个架构论断都要锚到仓库里的证据,假设必须显式。这两句合起来,等于给模型上了双锁:不许泛泛而谈,也不许把推测写成事实。注意它把「假设」的处理方式定为「显式保留」而不是「消除」——这是对模型能力边界的清醒认识,建模场景里有些信息就是拿不到,与其让模型编,不如让它把假设摆在台面上。
Quick start 部分列了四样输入:仓库根路径与在册路径、用途与部署形态、已有的架构摘要,以及 references 目录里的提示词模板。关键一句是:
Follow the required output contract in
references/prompt-template.md. Use it verbatim when possible.
「尽量逐字使用」——这是渐进披露的典型写法。SKILL.md 本体只说「有一份输出合同在隔壁」,具体格式细节全部下沉到 references/prompt-template.md,需要时才加载。正文里只出现合同的存在和地位,不复印合同内容,省下的正是每次会话都要付的 token 成本。同目录还有一份可选的 references/security-controls-and-assets.md,末尾一句「Only load the reference files you need」把按需加载说成了明规则。
整个流程八步,环环相扣。先看图:
flowchart TD
S1["1 划成分定范围"] --> S2["2 画边界列资产"]
S2 --> S3["3 校准攻击者能力"]
S3 --> S4["4 威胁写成滥用路径"]
S4 --> S5["5 概率乘影响排座次"]
S5 --> S6["6 暂停向用户求证"]
S6 -->|用户不答| S7["7 带假设写缓解"]
S6 -->|确认后| S7
S7 --> S8["8 自检清单过一遍"]
S8 --> OUT["落盘威胁模型报告"]
第1步划成分,最容易被忽略的卫生条款在这里:
Separate runtime behavior from CI/build/dev tooling and from tests/examples.
把运行时和 CI、构建、测试分开——威胁建模最经典的误报来源就是把测试样例里的危险函数当成生产代码。这一句是无数真实事故换来的经验。同一步里还有那句反幻觉铁律:Do not claim components, flows, or controls without evidence,没有证据不许声称任何组件、流程或控制的存在。
第2步画边界,要求把信任边界写成组件之间具体的「边」,每条边注明协议、认证、加密、校验、限流。资产清单和入口点清单并列:端点、上传面、解析器、任务触发器、管理工具、日志出口——这份入口点枚举本身就是一份不错的攻击面备忘录。
第3步校准攻击者,藏着一个罕见条款:
Explicitly note non-capabilities to avoid inflated severity.
明确写出攻击者「不具备」的能力,防止严重性虚高。市面上绝大多数安全提示词都在教模型往重里说,这一句反着来,教模型往回收。定罪文书里写「被告人不可能做到X」,和写「能做到X」同样重要。
第4步威胁写成滥用路径,要求威胁挂在资产和边界上,按攻击者目标分类——外泄、提权、完整性破坏、拒绝服务——并留了一句:
Keep the number of threats small but high quality.
威胁数量要少、质量要高。反灌水条款。模型天然倾向于列表越长越显得卖力,这句直接把评分标准改成「少而准」。
第5步排座次,定性和定量的混合:可能性与影响各给低中高三档,各配一句理由,优先级等于两者相乘,再按已有控制措施调整,最后要求写明「哪些假设最影响这个排名」——排名不只给结论,还要给出敏感性分析。
第6步是全文件的灵魂,一个停机点:
Pause and wait for user feedback before producing the final report.
出终审报告之前,强制暂停,把影响排名的关键假设汇总给用户确认,只问一到三个靶向问题。更难得的是降级路径也写死了:
If the user declines or can't answer, state which assumptions remain and how they influence priority.
用户不答或者答不上,不许卡死,改为声明剩余假设及其对优先级的影响。自动化的热情和人工确认的必要性,被一段话同时照顾到。对比市面上大量「一口气跑到底」的 Agent 技能,这一步停机点是把「人是最终责任人」写进了流程。
第7步写缓解,教科书级的一段对照直接嵌在正文里:建议要绑到具体位置和控制类型,宁可写「在网关对上传载荷强制 schema 校验」,不要写「校验输入」。泛泛建议和可执行建议的差别,一个例句讲完。已存在的缓解措施和推荐的缓解措施必须分开列,前者要有证据。
第8步自检,六条确认:入口点全覆盖、每条信任边界都有对应威胁、运行时与 CI 分离、用户澄清或明确未答已反映、假设与开放问题显式、格式符合隔壁那份合同。自检的最后一件事是落盘,连文件名都是合同:
Write the final Markdown to a file named
<repo-or-dir-name>-threat-model.md
用仓库目录名做报告文件名,下次重跑天然覆盖旧版,也方便脚本化检索。命名即接口,这是很多技能作者想不到的细节。
工作流之后附了一段「示例性质」的风险分级指引:预认证 RCE、认证绕过、跨租户访问、密钥窃窃、沙箱逃逸归高;定向打关键组件的 DoS、部分数据暴露、有实际影响的限流绕过、能干扰检测的日志投毒归中;低敏感信息泄露、易缓解的噪音 DoS、前置条件苛刻的问题归低。标明 illustrative, not exhaustive——给锚点但不封死,和开头「不做通用清单」的立场自洽:清单可以有,但只当例子。
security-best-practices 的结构是另一个流派的范本:先识别项目里所有语言和框架,前端后端都要认,然后去 references/ 里按 <语言>-<框架>-<栈>-security.md 的命名规则取对应文档,读全再动手。参考文档没有覆盖的栈,才回退到模型自己的常识,而且一旦用户要正式报告,必须先声明「这块没有具体指引」。
它定义了三种工作模式:写新代码时默认按安全写法落笔;日常改代码时被动监测,只挑影响最大的问题举手;用户点名要报告时才出全量报告——按严重度分节、每条 findings 编号、关键条目一句话影响声明、引用代码必须带行号。报告写完落盘,还要口头向用户汇报并告知文件位置,闭环到人。
最值得抄的是 Overrides 一节。项目文档或提示词里明确要求绕过某些安全实践时:
you MAY report it to user, but do not fight with them.
可以提醒,但不许吵架。绕过时建议顺手把「为什么这条实践在这里不适用」写进项目文档,下次不再纠结。安全工具最招人烦的就是拿着规范砸人脸,这一段把「工具的边界」写进了工具自身。
修复环节同样老练:一次只修一条;每处修改注明依据的是哪条实践、不这么写会怎样;先想清楚会不会破坏现有功能——原文那句观察相当通透:不安全的代码能活这么久,往往是因为有别的代码赖着它。所以修复宁可深思熟虑,不要速战速决,改完要走用户既有的测试和提交流程。
文末的通用建议里有两条实战智慧:对外暴露的资源别用自增 ID,换 UUID 防枚举;TLS 一节提醒开发期大多没有 TLS,不要把「没上 TLS」当漏洞报,HSTS 更是慎之又慎——没吃透就推荐,分分钟造成持续性的宕机和用户锁死。
顺带一提,这份 SKILL.md 结尾留下了一个有趣的指纹:
...not generally recommended for the scope of projects being reviewed by codex.
全文唯一一次出现的小写 codex。大概率是作者从别处改写时漏改的残留,推测它最早面向的评审对象另有其家——一份提示词里的出身痕迹,比任何宣传语都诚实。
第三件 security-ownership-map 走的是重脚本路线。它从 git 历史里建两种图:人和文件的两部图(谁碰过哪些文件),以及文件共变图(常一起被改的文件之间按 Jaccard 相似度连边),在共变图上跑社区发现聚类。敏感路径默认按 auth、crypto、secrets 一类规则打标,可用 CSV 覆盖;依赖机器人提交、合并提交、锁文件和编辑器配置这类「胶水文件」默认排除,让聚类反映真实代码移动而不是基础设施改动。
它真正的设计亮点在「context 经济学」:分析产物落成 people.csv、files.csv、edges.csv、summary.json 等一整套文件,但模型不直接读大文件,而是通过 query_ownership.py 取「有界的 JSON 切片」——原文的说法是 small, JSON-bounded slices without loading the full graph into context。预置的查询口子全对着安全场景:孤儿敏感代码(长期没人碰且 bus factor 为 1)、隐藏所有者(不挂名却控制六成认证代码的人)、低 bus factor 的敏感热点、谁动敏感代码最多、某文件的共变邻居、某社区当前的维护者。产物甚至带了按提交时区偏移推断贡献者时区的字段,summary 建议最后和 CODEOWNERS 对比,突出所有权漂移。
这份 SKILL.md 也留了一个出身上的小破绽:正文示例里的脚本路径写的是 skills/skills/security-ownership-map/scripts/...,skills 两层嵌套,明显是从某个把技能包套在 skills 目录下的仓库里整体搬出时留下的痕迹。和 best-practices 里那个 codex 一样,这些指纹提示它们出身于实战项目,而不是为发而写的演示品。
flowchart TD
G["git log 历史"] --> P["people.csv 人节点"]
G --> F["files.csv 文件节点"]
P --> E["edges.csv 触碰边"]
F --> E
F --> C["共变边 Jaccard 权重"]
C --> D["社区发现聚类"]
D --> S["summary.json 风险清单"]
S --> Q["查询脚本按片取用"]
threat-model 适合:接手陌生仓库前摸清攻击面、上线前对新增外部入口做专项评审、给安全团队产出可讨论的建模文档。它不适合当扫描器用——没有污点分析、没有依赖审计,产出是推理文档而非漏洞列表;也不适合特别小的脚本项目,八步流程对一个三百行的工具纯属杀鸡用牛刀。
best-practices 适合随装随用,写新项目时收益最大;它的软肋是 references 覆盖面决定上限,栈冷门时退化成模型常识。ownership-map 适合中型以上、git 历史够长的仓库,需要装 networkx、会看 CSV;刚起步两周的仓库翻不出有意义的所有权结构。
三件均为标准目录结构(SKILL.md 加 references 与 scripts),装法一致:把技能目录放进 ~/.claude/skills/,Claude Code 会按目录名自动发现。ownership-map 需要补一个依赖:
pip install networkx
触发靠自然语言即可:「给这个仓库做一次威胁建模」「按安全最佳实践写这个接口」「把这个仓库的所有权风险算一遍」。用 ownership-map 的脚本时记着它同门 webapp-testing 一系流传的黑盒纪律:先跑 --help 看用法,不要一上来读脚本源码污染上下文。
这轮拆解最大的收获不是哪一件功能强,而是三件合起来示范了提示词工程里最容易被忽视的一层:流程纪律。threat-model 教「证据与暂停」,best-practices 教「克制与闭环」,ownership-map 教「产物与切片」。技能写得好不好,看的不只是指令多详细,而是作者有没有把「模型会怎么偷懒、用户会在哪一步缺席、上下文会在哪里爆炸」这三个问题提前想清楚,再用条款把它们逐一堵上。三份文件,三个回答,都值得在做自己的第一个 Skill 前通读一遍。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
