前言¶
Semgrep 是目前安全工程裏很常見的靜態分析工具,用 YAML 規則去匹配代碼模式,既能掃注入、危險 API,也能把團隊內部的編碼規範固化進 CI。問題在於:規則本身並不好寫。
只寫「能打中漏洞」的那一半,通常會把安全的寫法一併報出來;寫得太死,換一種調用方式就漏報。污點分析(taint mode)能跟蹤「不可信數據有沒有流到危險函數」,但 source、sink、sanitizer 怎麼寫、測試怎麼標,文檔分散,Agent 如果只憑印象生成一份 YAML,很容易出現假陽性過高、測例不全、一條文件裏塞多條規則這類問題。
Trail of Bits 把這件事做成了 Agent Skill:semgrep-rule-creator。它不負責替你跑現成規則集,而是約束 Agent 按「先寫測試、再看 AST、再寫規則、測通後再優化」的流程,產出可以交給 semgrep --test 驗證的規則。下面按官方倉庫和 SKILL.md 原文說明它是什麼、怎麼裝、怎麼用。
這是什麼¶
semgrep-rule-creator 是 Trail of Bits 安全技能市場(trailofbits/skills)裏的一個插件,用來創建可檢測安全漏洞、Bug 模式和代碼模式的自定義 Semgrep 規則。插件作者是 Maciej Domanski,當前插件元數據裏的版本是 1.2.2。Skill 本體在:
https://github.com/trailofbits/skills/tree/main/plugins/semgrep-rule-creator/skills/semgrep-rule-creator
它基於通用的 SKILL.md 格式,Claude Code、Codex CLI、Cursor 這類 AI 編程工具都可以加載。官方倉庫把它定位成 Claude Code 插件市場中的一項;Codex 可以通過 Claude marketplace 兼容方式加載同一套市場。倉庫採用 Creative Commons Attribution-ShareAlike 4.0 許可。
官方 README 寫明的使用時機是:
- 爲特定 Bug 模式寫 Semgrep 規則
- 爲代碼庫裏的安全漏洞寫檢測規則
- 寫污點模式規則,做數據流分析
- 寫模式匹配規則,做代碼質量或編碼規範檢查
明確不要用它的場景是:跑已有 Semgrep 規則集,以及不做自定義規則的通用靜態分析。後者官方指向同一市場裏的 static-analysis Skill。
前置條件很直接:本機要先裝好 Semgrep。
pip install semgrep
# 或
brew install semgrep
核心能力¶
這個 Skill 真正約束的是「怎麼寫規則」,而不是再封裝一層 Semgrep CLI。對照 SKILL.md 和插件 README,能力可以概括成下面幾條。
1、強制測試先行。先寫帶 # ruleid: / # ok: 註解的測試文件,再寫 YAML。只覆蓋漏洞用例、不寫安全用例,會被明確當成反模式:能打中漏洞只完成了一半,安全寫法不能誤報,否則規則在生產環境裏很難建立信任。
2、先看 AST 再寫 pattern。Semgrep 匹配的是抽象語法樹,不是源碼字符串。foo.bar() 和 foo().bar 看起來接近,解析結果可以完全不同。Skill 要求用 semgrep --dump-ast 看清結構,再寫模式。
3、數據流問題優先用 taint mode。純語法匹配 eval($X) 會同時打中 eval(user_input) 和 eval("safe_literal")。污點模式跟蹤「不可信數據是否真的流到 sink」,注入類問題的誤報通常會低很多。官方也允許在兩種路線之間切換:taint 傳播不符合預期時改回 pattern matching;pattern 對安全用例誤報太多時再改 taint。目標是規則能用,而不是綁死某一種寫法。
4、一份 YAML 只放一條規則。輸出固定爲「以 rule-id 命名的目錄 + 一條 YAML + 一份測試文件」,不把多條規則塞進同一個文件。
5、寫規則前要求 Agent 先拉取 Semgrep 官方文檔:規則語法、模式語法、規則測試、污點分析概覽與進階、常量傳播,以及 Trail of Bits Testing Handbook 裏的 Semgrep 章節。本地還帶了兩份參考:references/quick-reference.md(命令、算子、taint 語法)和 references/workflow.md(完整工作流與示例)。
插件裏還有一條 Claude Code 命令 trailofbits:semgrep-rule,會根據當前對話裏的漏洞模式、目標語言、是否適合 taint,去調用這個 Skill 的完整流程;上下文不夠時會先問清楚要檢測什麼。
安裝與啓用¶
Trail of Bits 官方倉庫給出的安裝方式以 Claude Code 插件爲主。
先把市場加進來,再安裝這個插件:
/plugin marketplace add trailofbits/skills
/plugin install trailofbits/skills/plugins/semgrep-rule-creator
也可以用 /plugin menu 在市場裏瀏覽後安裝。插件名爲 semgrep-rule-creator。
Codex 官方說明支持直接加載 Claude 插件市場,不需要額外的 sidecar 元數據:
codex plugin marketplace add trailofbits/skills
codex plugin list
codex plugin add semgrep-rule-creator@trailofbits
如果使用通用的 skills CLI(officialskills.sh 上的安裝說明),可以用:
npx skills add https://github.com/trailofbits/skills --skill semgrep-rule-creator
裝好之後,在對話裏直接描述要檢測的模式即可,例如「爲 Python 寫一條 taint 規則,捕獲 request.args 流入 eval()」,或使用上面的 /semgrep-rule 命令。Skill 聲明可調用的工具是 Bash、Read、Write、Edit、Glob、Grep、WebFetch,也就是允許 Agent 讀文檔、改文件、跑 Semgrep 命令。
寫規則的工作流¶
Skill 把流程寫成一份必須勾完的清單,官方標註爲 strict,步驟不能跳。
Semgrep Rule Progress:
- [ ] Step 1: Analyze the Problem
- [ ] Step 2: Write Tests First
- [ ] Step 3: Analyze AST structure
- [ ] Step 4: Write the rule
- [ ] Step 5: Iterate until all tests pass (semgrep --test)
- [ ] Step 6: Optimize the rule (remove redundancies, re-test)
- [ ] Step 7: Final Run
各步在 workflow.md 裏的要求如下。
Step 1 分析問題。 先讀文檔,再用「能講給初級開發聽懂」的方式說清楚要檢測的漏洞或模式,確認目標語言,再決定用 pattern matching 還是 taint mode。taint 適合跨變量、跨函數跟蹤不可信數據,尤其是 SQL 注入、命令注入、XSS 這類問題,也更不容易被 if、循環等結構打散。
Step 2 先寫測試。 目錄結構必須是:
<rule-id>/
├── <rule-id>.yaml # Semgrep 規則
└── <rule-id>.<ext> # 帶 ruleid/ok 註解的測試文件
測試註解只允許 ruleid: 和 ok:,禁止 todoruleid:、todook:,也不要用多行註釋來標。註解必須單獨一行,並且緊挨在目標代碼的上一行——Semgrep 報的是註解後面那一行。測試要同時覆蓋:明確的漏洞用例、明確的安全用例、邊界與不同寫法、經過 sanitize/校驗的輸入、完全無關的正常代碼,以及寫在 if、循環、try/catch、回調裏的嵌套情況。
Step 3 分析 AST。
semgrep --dump-ast --lang <language> <rule-id>.<ext>
看函數調用怎麼表示、變量怎麼綁定、控制流怎麼展開,避免寫出「人眼覺得對、樹結構對不上」的 pattern。
Step 4 寫規則並校驗。 規則必填字段在 quick-reference 裏寫得很清楚:id、languages、severity(LOW / MEDIUM / HIGH / CRITICAL)、message,以及 pattern / patterns / pattern-either / mode: taint 之一。寫完後:
semgrep --validate --config <rule-id>.yaml
cd <rule-directory>
semgrep --test --config <rule-id>.yaml <rule-id>.<ext>
期望輸出是 1/1: ✓ All tests passed。taint 規則調試可以用:
semgrep --dataflow-traces --config <rule-id>.yaml <rule-id>.<ext>
它會打出 source、sink、數據流路徑,以及 taint 沒有傳播下去的原因。
Step 5 迭代到全部通過。 「大多數測試通過」不算完成。漏報通常是 pattern 太死,需要 pattern-either;誤報通常是 pattern 太寬,需要 pattern-not 或收緊 sanitizer。
Step 6 最後才優化。 全部測通之後再刪冗餘:引號變體、被 ... 覆蓋的子集、可以用 metavariable-regex 合併的相似調用。每改一次都必須重新跑測試,因爲有些看起來重複的 pattern,其實對應不同的 AST。
Step 7 終驗。 用 semgrep --config 真正跑一遍規則。message 要短、說明匹配到了什麼,且不能留下未插值的元變量(例如 $OP、$VAR)——message 裏提到的元變量必須能被 pattern 捕獲。
官方示例:eval 污點規則¶
SKILL.md 的 Quick Start 給了一條 Python 規則,檢測用戶輸入進入 eval()。規則文件可以理解爲 insecure-eval.yaml:
rules:
- id: insecure-eval
languages: [python]
severity: HIGH
message: User input passed to eval() allows code execution
mode: taint
pattern-sources:
- pattern: request.args.get(...)
pattern-sinks:
- pattern: eval(...)
對應測試文件 insecure-eval.py:
# ruleid: insecure-eval
eval(request.args.get('code'))
# ok: insecure-eval
eval("print('safe')")
在規則目錄裏執行 semgrep --test。這條規則用 taint,而不是 pattern: eval(...),因此字面量調用可以標成 ok,不會被當成漏洞。
官方還給出了幾類要避免的寫法,和上面的流程是配套的。
模式過寬,等於沒有檢測能力:
# BAD: 匹配任意函數調用
pattern: $FUNC(...)
# GOOD: 對準具體的危險函數
pattern: eval(...)
測試只寫漏洞、不寫安全用例:
# BAD: 只有漏洞用例
# ruleid: my-rule
dangerous(user_input)
# GOOD: 同時寫安全用例,用來卡住誤報
# ruleid: my-rule
dangerous(user_input)
# ok: my-rule
dangerous(sanitize(user_input))
# ok: my-rule
dangerous("hardcoded_safe_value")
模式過死,換一種拼接方式就漏報;數據流類問題應改用 taint:
# BAD: 只匹配這一種字符串拼接
pattern: os.system("rm " + $VAR)
# GOOD: 跟蹤「輸入是否流到 os.system」
mode: taint
pattern-sources:
- pattern: input(...)
pattern-sinks:
- pattern: os.system(...)
taint 規則裏還可以加 pattern-sanitizers,把 sanitize(...)、escape(...) 這類函數標成消毒點。quick-reference 裏還列出了 exact、by-side-effect 等選項,用來控制「整次調用算 source / 只有某個參數算 source」。這些細節以 Semgrep 文檔和 Skill 自帶的 quick-reference 爲準,寫規則時讓 Agent 去讀,不必憑記憶填。
適用場景與注意¶
官方和 Skill 索引頁列出的典型用法包括:
- 寫 taint 規則,檢測用戶可控的請求參數流入 SQL 執行點
- 在 Python 代碼裏捕獲
eval()/exec()喫不可信輸入 - 在大倉庫裏標記已廢棄 API,做編碼規範
- 安全審計裏發現某一類漏洞後,補一條可迴歸的檢測規則
- 把倉庫特有的 Bug 模式做成自定義規則,放進 CI
同一市場裏還有兩個經常一起出現的 Skill:semgrep-rule-variant-creator 用來把已有規則移植到另一種語言;variant-analysis 用來在代碼庫裏找同類漏洞。需要的是「跑掃描、看 SARIF」,而不是寫新規則時,應改用 static-analysis。
使用時有幾條硬約束,漏掉就會寫出不能上生產的規則:
- 必須先裝 Semgrep,Skill 本身不替代掃描器
- 測試必須 100% 通過,優化只能發生在全部通過之後
- 目標語言不要用
languages: generic做泛化匹配 - 一個 YAML 文件只放一條規則
- 測試註解不要夾雜其他文字,也不要用
todoruleid/todook當「以後再修」的佔位 - 元變量必須大寫,例如
$X、$FUNC,不能寫成$x
另外,這個 Skill 不會幫你選擇現成的 p/security-audit、p/trailofbits 這類規則集,也不會替你配置 CI 流水線。它的產出是「一條經過測試的自定義規則」;真正掃倉庫、進流水線,還是要用 Semgrep 自己的命令和配置。
小結¶
手寫 Semgrep 規則最常見的失敗不是 YAML 語法錯,而是 pattern 過寬、過死,以及沒有用安全用例把誤報卡住。semgrep-rule-creator 把 Trail of Bits 的規則寫作習慣寫成 Agent 必須遵守的清單:先測試、再 AST、數據流優先 taint、測通再優化、一文件一條規則。
官方地址:
- Skill 目錄:https://github.com/trailofbits/skills/tree/main/plugins/semgrep-rule-creator/skills/semgrep-rule-creator
- 插件說明:https://github.com/trailofbits/skills/tree/main/plugins/semgrep-rule-creator
- 技能市場:https://github.com/trailofbits/skills
- 索引頁:https://officialskills.sh/trailofbits/skills/semgrep-rule-creator