安全测试
- 作者仓库星标 5,723
- 叉子 499
- 作者更新于 2026年6月15日 16:05
- 作者仓库 skills
- 领域
- AI 智能
- 兼容 Agent
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- 信任分
- 88 / 100 · 社区维护
- 作者 / 版本 / 许可
- @trailofbits · 未声明 license
- Token 消耗评级
- 低消耗
- 接入复杂程度
- 需手动接入
- 是否需要外部 API Key
- 需要 · Vendor-specific
- 兼容的系统
- 未声明(默认跨平台)
- 底层运行要求
- 无特殊要求
- 文件与系统权限
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 网络行为
- 允许外网请求
- 安装命令数
- 26 条
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: mermaid-to-proverif
description: Translates Mermaid sequenceDiagrams describing cryptographic protocols into ProVerif formal veri…
category: AI 智能
runtime: 无特殊运行时
---
# mermaid-to-proverif 输出预览
## PART A: 任务判断
- 适用问题:提示词、Agent 工作流、模型评估或自动化推理。
- 输入要求:目标材料、限制条件、期望输出和验收方式。
- 证据边界:围绕“When to Use / When NOT to Use / Rationalizations to Reject”读取原文规则,不把推断写成作者承诺。
## PART B: 执行结果
- **01** 任务判断:确认你的需求是否属于提示词、Agent 工作流、模型评估或自动化推理,并标出输入、限制和预期结果。
- **02** 执行计划:优先按“When to Use / When NOT to Use / Rationalizations to Reject”拆成步骤,说明每一步会读取什么、修改什么、产出什么。
- **03** 交付结果:给出可复制的命令、文件改动、检查清单或内容草稿,并说明如何继续迭代。
- **04** 风险边界:结合 读取文件、写入/修改文件、执行终端命令、会按任务需要访问外部网络、需要准备 Vendor-specific API Key 给出执行前确认项。
## Running Rules
- 读取文件、写入/修改文件、执行终端命令;会按任务需要访问外部网络;需要准备 Vendor-specific API Key。
- 先小样例验证,再放大到真实任务。
- 交付时同时给结果、检查口径和下一步迭代建议。 原文没有稳定的斜杠命令要求。安装验证后通常全局生效,直接在对话里点名这个 Skill 并描述任务即可。
告诉 Agent 目标文件或材料、期望结果、不可改范围、是否允许联网或执行命令。本 Skill 的权限画像是:读取文件、写入/修改文件、执行终端命令。
先用一个小任务确认它会围绕“When to Use / When NOT to Use / Rationalizations to Reject”工作;涉及文件或命令时,先看 diff、日志、预览或测试结果。
检查最终产物是否包含明确结果、必要证据和下一步动作;如果输出泛泛而谈,就补充输入、边界和验收标准后重跑。
---
name: mermaid-to-proverif
description: Translates Mermaid sequenceDiagrams describing cryptographic protocols into ProVerif formal veri…
category: AI 智能
source: trailofbits/skills
---
# mermaid-to-proverif
## 什么时候使用
- 把AI / Agent方向的常用动作沉淀成 Agent 可调用的技能 适合处理AI Agent、提示词、模型评估与自动化推理,核心价值是把输入、判断、执行、验证和交付边界固定下来,避免 Agent 泛泛回答。 把任务拆成可执行、可检查…
- 面向提示词、Agent 工作流、模型评估或自动化推理,优先处理能明确输入、步骤和验收标准的工作。
## 需要提供什么
- 目标材料、目录范围、期望结果和不可改动内容。
- 是否允许联网、执行命令、读写文件或调用外部服务。
## 执行规则
- 围绕「When to Use / When NOT to Use / Rationalizations to Reject」组织步骤,不把推断写成作者事实。
- 读取文件、写入/修改文件、执行终端命令;会按任务需要访问外部网络;需要准备 Vendor-specific API Key。
- 先跑小样例,确认结果可检查后再扩大任务范围。
## 输出要求
- 给出最终产物、关键证据、验证方式和下一步动作。
- 信息不足时标记 unknown,不编造命令、平台或依赖。 作者原文负责流程事实;仓库文件负责来源和命令;流狐只补充适用场景、限制和质量判断。
skill "mermaid-to-proverif" {
输入层 -> 用户目标 + 目标文件 + 禁止范围 + 验收标准
上下文层 -> When to Use / When NOT to Use / Rationalizations to Reject
规则层 -> SKILL.md 触发条件 / 执行顺序 / 输出格式
运行层 -> 无特殊运行时 | 读取文件、写入/修改文件、执行终端命令 | 会按任务需要访问外部网络
安全层 -> 需要准备 Vendor-specific API Key + 小任务验证 + diff / 日志复核
输出层 -> 可复制结果 + 检查清单 + 下一步迭代
} Mermaid to ProVerif
Reads a Mermaid sequenceDiagram describing a cryptographic protocol and
produces a ProVerif model (.pv file) that can be passed directly to the
ProVerif verifier.
Tools used: Read, Write, Grep, Glob.
The typical input is the output of the crypto-protocol-diagram skill — a
Mermaid sequenceDiagram annotated with cryptographic operations (Sign,
Verify, DH, HKDF, Enc, Dec, etc.) and message arrows.
When to Use
- User asks to formally verify a cryptographic protocol described as a Mermaid sequenceDiagram
- User wants to generate a ProVerif model (.pv file) from a protocol diagram
- User wants to prove secrecy, authentication, or forward secrecy properties
- Input is the output of the
crypto-protocol-diagramskill
When NOT to Use
- No Mermaid sequenceDiagram exists yet — use
crypto-protocol-diagramfirst to generate one - User wants to verify properties of non-cryptographic systems (state machines, access control)
- User wants to run ProVerif on an existing .pv file — just run
proverif model.pvdirectly
Rationalizations to Reject
| Rationalization | Why It's Wrong | Required Action |
|---|---|---|
| "Reachability queries are just busywork" | If events aren't reachable, all other query results are meaningless | Always add reachability queries first as a sanity check |
| "Public channels are fine for all messages" | Private channels for internal state prevent false attacks | Use private channels for intra-process state threading |
| "I'll skip the forward secrecy test" | Ephemeral keys demand forward secrecy verification | Add the ForwardSecrecyTest process whenever the diagram shows ephemeral keys |
| "Unused declarations are harmless" | ProVerif may report spurious results from orphan declarations | Clean up all unused types, functions, and events |
| "The model compiles, so it's correct" | A compiling model can have dead receives, type mismatches, or impossible guards that make queries vacuously true | Validate reachability before trusting any security query |
| "I don't need to check the example first" | The example defines the expected output quality bar | Study examples/simple-handshake/ before working on unfamiliar protocols |
Workflow
ProVerif Model Progress:
- [ ] Step 1: Parse participants and channels
- [ ] Step 2: Inventory cryptographic operations
- [ ] Step 3: Declare types, functions, and equations
- [ ] Step 4: Identify and declare events
- [ ] Step 5: Formulate security queries
- [ ] Step 6: Write participant processes
- [ ] Step 7: Write main process and finalize
- [ ] Step 8: Verify and deliver
Step 1: Parse Participants and Channels
From the Mermaid diagram:
- Extract every
participantoractordeclaration. Each becomes a ProVerif process. - Count message arrows (
->>,-->>,-x,--x). Each distinctA ->> B: labelcreates a communication step on a channel. - Decide channel model:
- Public channel for any message sent over the network before a secure channel is established (e.g., ClientHello, ephemeral keys, ciphertext to be decrypted by the peer).
- Private channel only for internal state threading within a single party process (not for cross-party messages).
- Default: declare one shared public channel
cfor all cross-party messages. Add per-flow channels only when two distinct parallel sessions must be independent.
free c: channel.
Step 2: Inventory Cryptographic Operations
Walk through every Note over annotation and message label. Build a list of
all distinct operations used. Map each to a ProVerif declaration category:
| Mermaid annotation | ProVerif category |
|---|---|
keygen() → sk, pk |
New name (new sk), public key derived via function |
DH(sk_A, pk_B) |
DH function or exp with group |
Sign(sk, msg) → σ |
Signature function |
Verify(pk, msg, σ) |
Equation or destructor |
Enc(key, msg) → ct |
Symmetric or asymmetric encryption function |
Dec(key, ct) → msg |
Destructor (equation) |
HKDF(ikm, info) → k |
PRF/KDF function |
HMAC(key, msg) → tag |
MAC function |
H(msg) → digest |
Hash function |
Commit(v, r) → C |
Commitment function |
Open(C, v, r) |
Commitment equation |
Consult references/crypto-to-proverif-mapping.md for exact ProVerif syntax for each.
Step 3: Declare Types, Functions, and Equations
Build the cryptographic preamble in this order:
- Types — declare custom types used to distinguish key material:
type key.
type pkey. (* public key *)
type skey. (* secret key *)
type nonce.
- Constants — for fixed strings used as domain separators or labels:
const msg1_label: bitstring.
const msg2_label: bitstring.
const info_session_key: bitstring.
- Functions — constructors and destructors. Destructors use inline
reducso that the process aborts on verification or decryption failure:
(* Asymmetric encryption *)
fun aenc(bitstring, pkey): bitstring.
fun adec(bitstring, skey): bitstring
reduc forall m: bitstring, k: skey;
adec(aenc(m, pk(k)), k) = m.
fun pk(skey): pkey.
(* Symmetric encryption / AEAD *)
fun aead_enc(bitstring, key): bitstring.
fun aead_dec(bitstring, key): bitstring
reduc forall m: bitstring, k: key;
aead_dec(aead_enc(m, k), k) = m.
(* Digital signatures — verify returns the message on success, aborts on failure *)
fun sign(bitstring, skey): bitstring.
fun verify(bitstring, bitstring, pkey): bitstring
reduc forall m: bitstring, k: skey;
verify(sign(m, k), m, pk(k)) = m.
(* KDF — first arg is key (from DH), second is bitstring (info/context) *)
fun hkdf(key, bitstring): key.
(* MAC *)
fun mac(bitstring, key): bitstring.
(* Hash *)
fun hash(bitstring): bitstring.
(* DH *)
fun dh(skey, pkey): key.
fun dhpk(skey): pkey.
(* Serialization — ProVerif is strongly typed: pkey cannot appear
* where bitstring is expected. Use these to build signed payloads. *)
fun pkey2bs(pkey): bitstring.
fun concat(bitstring, bitstring): bitstring.
- Equations — algebraic identities on constructors only (not on destructors, which already have their rewrite rules inline):
equation forall sk_a: skey, sk_b: skey;
dh(sk_a, dhpk(sk_b)) = dh(sk_b, dhpk(sk_a)).
Only declare what the diagram actually uses. Do not add functions for operations not present.
Step 4: Identify and Declare Events
Events mark security-relevant moments in the protocol execution. Extract them by identifying:
- Begin events (
event beginRole(params)): triggered immediately before a party sends a message that depends on a long-term identity commitment (e.g., right before sending a signed message or a MAC'd message). - End events (
event endRole(params)): triggered immediately after a party successfully verifies the peer's identity (e.g., afterVerify(...)or MAC check passes, session key confirmed). - Secrecy markers: any key or nonce that should remain unknown to the attacker after the handshake.
event beginI(pkey, pkey). (* pk_I, pk_R — fired before sending the signed message *)
event endI(pkey, pkey, key). (* pk_I, pk_R, session_key — fired after accepting *)
event beginR(pkey, pkey).
event endR(pkey, pkey, key).
Parameters should uniquely identify the session: the parties' public keys, plus the session key or a transcript hash.
Step 5: Formulate Security Queries
Write one query per security property. Choose from:
Reachability (always add first — structural sanity check):
Verify that the success events are actually reachable. If ProVerif reports any
of these as false, the model has a structural bug (dead receive, type mismatch,
impossible guard) and no other query result should be trusted. Once the model
is validated, comment them out if they slow down the main property checks:
(* Sanity: both endpoints must be reachable — comment out once validated. *)
(*
query pk_i: pkey, pk_r: pkey, k: key; event(endI(pk_i, pk_r, k)).
query pk_i: pkey, pk_r: pkey, k: key; event(endR(pk_i, pk_r, k)).
*)
Secrecy (key not derivable by attacker):
Declare a private free name and encrypt it under the session key. The attacker
knowing private_I is equivalent to breaking the session key:
free private_I: bitstring [private].
(* In process, after deriving sk_session: *)
out(c, aead_enc(private_I, sk_session));
(* Query: *)
query attacker(private_I).
Weak authentication (if B accepted, A ran at some point with matching params — does not prevent replay):
query pk_i: pkey, pk_r: pkey, k: key;
event(endR(pk_i, pk_r, k)) ==> event(beginI(pk_i, pk_r)).
Injective authentication (prevents replay — each B-accept corresponds to a distinct A-run):
query pk_i: pkey, pk_r: pkey, k: key;
inj-event(endR(pk_i, pk_r, k)) ==>
inj-event(beginI(pk_i, pk_r)).
Forward secrecy: add a ForwardSecrecyTest process to the main process
that leaks both long-term secret keys to the attacker, then check that a past
session key remains secret. Pair it with a free fs_witness: key [private]
declaration and query attacker(fs_witness). See
references/security-properties.md →
Forward Secrecy, and the worked example in
examples/simple-handshake/sample-output.pv.
Choose the strongest applicable query for each property. See references/security-properties.md for the full decision tree.
Step 6: Write Participant Processes
Write one let process per participant. Structure each process to mirror the
Mermaid diagram step-by-step, in order.
Template for a two-party protocol:
let Initiator(sk_I: skey, pk_R: pkey) =
(* Step: generate ephemeral key *)
new ek_I: skey;
let epk_I = dhpk(ek_I) in
(* Step: sign and send msg1 — pkey2bs casts pkey to bitstring *)
let sig_I = sign(concat(msg1_label, pkey2bs(epk_I)), sk_I) in
event beginI(pk(sk_I), pk_R);
out(c, (epk_I, sig_I));
(* Step: receive msg2 *)
in(c, (epk_R: pkey, sig_R: bitstring));
(* Step: verify responder signature — destructor aborts on failure *)
let transcript = concat(pkey2bs(epk_I), pkey2bs(epk_R)) in
let _ = verify(sig_R, concat(msg2_label, transcript), pk_R) in
(* Step: derive session key *)
let dh_val = dh(ek_I, epk_R) in
let sk_session = hkdf(dh_val, concat(info_session_key, transcript)) in
event endI(pk(sk_I), pk_R, sk_session);
(* Secrecy witness: encrypt private_I under the session key.
* Declared as: free private_I: bitstring [private].
* The query attacker(private_I) checks the attacker cannot derive it. *)
out(c, aead_enc(private_I, sk_session)).
Rules for writing processes:
- Each
A ->> B: msg_contentsin the diagram becomes:out(c, msg_contents)in A's processin(c, x)(with matching destructuring) in B's process
- Each
Note over A: op → resultbecomes alet result = op inbinding - Each
Note over A: Verify(...)becomes alet _ = verify(...) inbinding (the destructor aborts on failure — no explicit else needed, modeling abort) - Use
altblocks in the diagram asif/then/elsein the process - Long-term keys are process parameters; ephemeral values use
new
N-party or MPC protocols: write one process per distinct role. For
threshold protocols, write a single role process and replicate it !N times
in the main process.
Step 7: Write Main Process and Finalize
The main process:
- Generates long-term keys with
new - Publishes public keys to the attacker via
out(c, pk(sk)) - Runs participant processes in parallel under replication (
!) to allow multiple sessions - Optionally leaks long-term keys for forward-secrecy analysis
process
new sk_I: skey; let pk_I = pk(sk_I) in out(c, pk_I);
new sk_R: skey; let pk_R = pk(sk_R) in out(c, pk_R);
(
!Initiator(sk_I, pk_R)
| !Responder(sk_R, pk_I)
)
Place the full file in this order:
(* 1. Channel declarations (free c: channel. / free ch: channel [private].) *)
(* 2. noselect directives (if needed for termination) *)
(* 3. Type declarations *)
(* 4. Constants *)
(* 5. Function declarations *)
(* 6. Equations (algebraic identities on constructors only) *)
(* 7. Table declarations *)
(* 8. Events *)
(* 9. Queries *)
(* 10. Let processes *)
(* 11. Main process *)
Step 8: Verify and Deliver
Before writing the file:
- Every participant in the diagram has a matching
letprocess - Every
out(c, ...)has a matchingin(c, ...)on the other side with compatible types - Every function used in a process is declared in the preamble
- Every destructor uses inline
reduc(not a separateequationblock) - Every event in a query is declared and triggered in a process
- Long-term public keys are output to channel
cin the main process (attacker can see them — that is the Dolev-Yao model) - No unused declarations (clean up anything added speculatively)
- If
tabledeclarations are present: everyinsert T(...)has a correspondingget T(...)with compatible column types and matching pattern constraints (=keyvs bare name) - If
noselectis used: its tuple structure matches the actual message shapes sent onc(e.g., pairs →mess(c, (x, y))) - If the Key Exposure Oracle pattern is used:
event key_exposed(sk_type)is declared, the oraclein(c, guess: sk_type); if pk(guess) = pk_new then event key_exposed(guess)appears at the end of the process that holds the secret, and the query isquery x: sk_type; event(key_exposed(x))
Write the model to a .pv file. Choose a filename from the protocol name,
e.g. noise-xx-handshake.pv or x3dh-key-agreement.pv.
After writing, print a brief summary:
Protocol: <Name>
Output: <filename>
Queries: <list each query and what property it tests>
Assumptions: <list modeling decisions and simplifications>
Decision Tree
├─ No Mermaid diagram provided?
│ └─ Ask the user: "Please provide the Mermaid sequenceDiagram,
│ or run the crypto-protocol-diagram skill first."
│
├─ Diagram uses DH (not just symmetric crypto)?
│ └─ Use dh/dhpk with commutativity equation
│ See references/crypto-to-proverif-mapping.md → DH section
│
├─ Diagram uses asymmetric signatures (Sign/Verify)?
│ └─ Use sign/verify with inline reduc (not equation)
│ verify returns the message on success; let _ = verify(...) in to abort on failure
│ Distinguish signing key (skey) from verification key (pkey)
│
├─ Diagram has an "alt" block (abort path)?
│ └─ Model as if/then only — the else branch aborts (process terminates)
│ Do NOT add out(c, error_message) unless the diagram shows it
│
├─ Protocol has N > 2 parties?
│ └─ Write one process per role, use ! for replication
│ Pass participant index as a parameter if roles differ by index only
│
├─ Forward secrecy requested?
│ └─ Add a ForwardSecrecy variant in the main process that leaks
│ long-term sk after session; add secrecy query for past session_key
│ See references/security-properties.md → Forward Secrecy
│
├─ Type-checker rejects the model?
│ └─ ProVerif is typed: check every function arg type matches declaration.
│ bitstring is the catch-all; key/pkey/skey/nonce are stricter.
│ Cast with explicit constructors when needed.
│
├─ Protocol has cross-process state coordination (e.g., one process must wait
│ for another to record acceptance before proceeding)?
│ └─ Use ProVerif tables (table/insert/get)
│ See references/proverif-syntax.md → Tables
│
├─ Verification does not terminate after several minutes?
│ └─ Add noselect directive matching the message tuple structure on c
│ See references/proverif-syntax.md → noselect
│
├─ Protocol generates a private-type key (type sk [private]) that is never
│ output directly but whose secrecy should be verified?
│ └─ Use the Key Exposure Oracle pattern instead of query attacker(sk)
│ See references/security-properties.md → Key Exposure Oracle
│
└─ Unsure which security properties to verify?
└─ Default set: secrecy of session key + injective authentication
(both directions). Add forward secrecy if diagram shows ephemeral keys.
Example
examples/simple-handshake/ contains a worked example:
diagram.md— Mermaid sequenceDiagram for a two-party authenticated key exchange (X25519 DH + Ed25519 signing + HKDF)sample-output.pv— exact ProVerif model the skill should produce, with secrecy and injective authentication queries
Study this before working on an unfamiliar protocol.
Supporting Documentation
- references/crypto-to-proverif-mapping.md — Mapping table from Mermaid cryptographic annotations to ProVerif function declarations, equations, and process patterns
- references/proverif-syntax.md — ProVerif language reference: types, functions, equations, processes, events, queries, and common pitfalls
- references/security-properties.md — Decision guide for choosing the right queries: secrecy, authentication (weak vs injective), forward secrecy, unlinkability, and how to model them
先判断是否适合
作者设计意图
作者的方法与取舍
边界和复核