mcpField
S
semgrep

semgrep

github.com/trailofbits安全7.9k9.6k 次安装今天更新
代码仓库

关于 semgrep

semgrep 是指导使用 Semgrep 对代码库进行静态安全扫描的 Skill,适合安全审计和代码审查前检查。它编排多语言规则集扫描,合并 SARIF 结果,并要求记录失败或跳过的扫描。

主要功能

  1. 01自动检测编程语言
  2. 02并行运行规则集扫描
  3. 03支持全量或重点结果模式
  4. 04合并 SARIF 扫描结果
  5. 05记录失败和跳过的扫描

适用场景

  1. 01审计代码库中的安全问题
  2. 02在代码审查前查找漏洞
  3. 03扫描已知缺陷模式
  4. 04汇总多个规则集的分析结果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/trailofbits/skills --skill semgrep

安装后在 Claude Code 中输入/semgrep确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
assets/
trail-of-bits-mark.svg
references/
rulesets.md
scan-modes.md
scripts/
merge_sarif.py
run-scans.sh
test_merge_sarif.py
workflows/
scan-workflow.md

详细介绍

Semgrep 安全扫描

运行 Semgrep 扫描,自动检测语言、并行执行,并合并输出 SARIF。

核心原则

  1. 始终使用 --metrics=off — Semgrep 默认会发送遥测数据;--config auto 也会向外发送数据。在安全审计期间,每条 semgrep 命令都必须包含 --metrics=off,以防止数据泄露。
  2. 用户必须批准扫描计划(步骤 3 是硬性门槛) — 用户原本提出的“扫描此代码库”请求不算批准。请列出确切的规则集、目标、引擎和模式;在用户明确回复“同意”或“继续”之前,不得启动扫描器。
  3. 第三方规则集是必需项,而非可选项 — Trail of Bits、0xdea 和 Decurity 规则可以发现官方注册表中不存在的漏洞。检测到的语言匹配时,必须包含这些规则集。
  4. 由 scripts/run-scans.sh 生成命令;不要自行编写 — 它会根据已批准的列表生成每条 semgrep 命令。这确保 --metrics=off、--include 范围限定规则和并行调度特性由代码保证,而非仅靠说明。提供已批准的规则集,然后让脚本运行。
  5. 扫描前始终检查是否有 Semgrep Pro — Pro 可启用跨文件污点跟踪,并多发现约 250% 的真阳性。跳过检查意味着会在不知情的情况下漏掉关键的文件间漏洞。
  6. 报告未运行的内容 — scans.json 除了 scans,还会记录 failed 和 skipped。无法克隆仓库的规则集,或扫描以非零状态码退出的情况,必须出现在报告中。将部分扫描报告为完整扫描,比完全不扫描更糟糕。

适用场景

  • 对代码库进行安全审计
  • 在代码审查前查找漏洞
  • 扫描已知的错误模式
  • 进行初步静态分析

不适用场景

  • 二进制分析 → 使用二进制分析工具
  • 已配置 Semgrep CI → 使用现有流水线
  • 需要跨文件分析,但没有 Pro 许可证 → 可考虑使用 CodeQL 替代
  • 创建自定义 Semgrep 规则 → 使用 semgrep-rule-creator 技能
  • 将现有规则移植到其他语言 → 使用 semgrep-rule-variant-creator 技能

输出目录

所有扫描结果、SARIF 文件和临时数据都会存储在同一个输出目录中。

  • 如果用户在提示中指定了输出目录,将其用作 OUTPUT_DIR。
  • 如果未指定,默认使用 ./static_analysis_semgrep_1。如果该目录已存在,则依次递增为 _2、_3 等。

无论哪种情况,写入任何文件之前,都必须使用 mkdir -p 创建目录。

# Resolve output directory
if [ -n "$USER_SPECIFIED_DIR" ]; then
  OUTPUT_DIR="$USER_SPECIFIED_DIR"
else
  BASE="static_analysis_semgrep"
  N=1
  while [ -e "${BASE}_${N}" ]; do
    N=$((N + 1))
  done
  OUTPUT_DIR="${BASE}_${N}"
fi
mkdir -p "$OUTPUT_DIR/raw" "$OUTPUT_DIR/results"

输出目录会在步骤 1 开始时解析一次,并在后续所有步骤中使用。

$OUTPUT_DIR/
├── rulesets.json                # The approved plan (Step 3), read by run-scans.sh (Step 4)
├── scans.json                   # What ran, failed, skipped, and covered nothing (Step 4)
├── raw/                         # Per-scan raw output (unfiltered)
│   ├── python-python.json        # <language>-<ruleset> for language-scoped rules
│   ├── python-python.sarif
│   ├── python-django.json
│   ├── python-django.sarif
│   ├── all-security-audit.json   # all-<ruleset> for cross-language rules, run once
│   ├── all-security-audit.sarif
│   └── ...
└── results/                     # Final merged output
    └── results.sarif

前提条件

必需: Semgrep CLI(semgrep --version)。如果尚未安装,请参阅 Semgrep 安装文档。

可选: Semgrep Pro — 可启用跨文件污点跟踪、过程间分析,以及更多语言(Apex、C#、Elixir)。使用以下命令检查:

# --metrics=off because Principle 1 has no exceptions, and this is the first semgrep command
# of a run. stderr is kept because "OSS only" has several causes (logged out, no subscription,
# registry blocked) and the run downgrades silently for all of them.
if PRO_ERR=$(semgrep --pro --validate --metrics=off --config p/default 2>&1); then
  echo "Pro available"
else
  echo "OSS only"
  echo "  reason: $(printf '%s' "$PRO_ERR" | tail -n 3)"
fi

限制: OSS 模式无法跟踪跨文件的数据流。Pro 模式使用 -j 1 进行跨文件分析(每个规则集的扫描速度较慢,但并行运行规则集可以弥补)。

扫描模式

在步骤 2 中选择模式。模式会影响扫描标志和后处理。

模式覆盖范围报告的发现
全部运行所有规则集、所有严重级别全部
仅重要项所有规则集,扫描前后均进行筛选仅安全漏洞,置信度和影响为中至高

仅重要项应用两层筛选:

  1. 预筛选:--severity WARNING --severity ERROR(CLI 标志)
  2. 后筛选:JSON 元数据 — 仅保留 category=security、confidence∈{MEDIUM,HIGH}、impact∈{MEDIUM,HIGH} 的结果

元数据筛选条件和 jq 筛选命令请参阅 scan-modes.md。

编排架构

┌──────────────────────────────────────────────────────────────────┐
│ MAIN SESSION (this skill)                                        │
│ Step 1: Detect languages + check Pro availability                │
│ Step 2: Select scan mode + rulesets (ref: rulesets.md)           │
│ Step 3: Present plan + rulesets, get approval [⛔ HARD GATE]     │
│ Step 4: Run scripts/run-scans.sh with the approved rulesets      │
│ Step 5: Post-filter, merge, report, delete repos/                │
└──────────────────────────────────────────────────────────────────┘
         │ Step 4: Bash
         ▼
┌──────────────────────────────────────────────────────────────────┐
│ scripts/run-scans.sh                                             │
│   clone       each third-party repo once, into repos/            │
│   generate    one semgrep command per ruleset                    │
│                ├── python     p/python, p/django   --include=*.py│
│                ├── javascript p/javascript         --include=*.js│
│                ├── docker     p/dockerfile                       │
│                └── cross-language  p/security-audit, p/secrets,  │
│                                    the cloned repos  (no filter) │
│   run         in batches of --jobs, exit code read per process   │
│   write       scans.json — scans, failed, skipped                │
└──────────────────────────────────────────────────────────────────┘

审批门槛保留在会话中;脚本只负责执行,不会询问任何内容。已批准的列表会以 JSON 文件的形式传入,因此扫描不会触及用户拒绝的规则集。

跨语言规则集放在一个共享单元中,而不是按语言重复。p/security-audit、p/secrets 和第三方仓库会对整个目标进行无范围限制的扫描,因此按语言各运行一次会重复执行相同的命令 N 次,并让 SARIF 合并来去重这些副本。

将其作为工作流运行

此插件提供 /static-analysis:semgrep-scan,可端到端运行整个扫描:检测语言和 Pro,从 rulesets.md 选择规则集,运行 scripts/run-scans.sh,合并并生成报告。请传入 JSON 对象,而不是散文:

/static-analysis:semgrep-scan {"target": "/abs/path", "mode": "run-all"}

它不会暂停以等待规则集审批。 使用目标调用它即表示选择加入,这与 /variant-analysis:variants 的工作方式相同。这样做是安全的,因为扫描只会读取目标,不会修改目标——没有 --autofix,所有写入都发生在输出目录中——因此,下方的审批门槛是范围确认,而非安全确认。无论如何,运行的内容都会记录在 rulesets.json 和 scans.json 中。

想要运行扫描时,请使用此工作流;如果规则集选择本身很重要,而且你想先查看并编辑列表,请按以下五个步骤操作。

工作流

请遵循 scan-workflow.md 中的详细工作流。 概要:

步骤操作门槛关键参考
1确定输出目录,检测语言和 Pro 是否可用—使用 Glob,而非 Bash
2选择扫描模式和规则集—rulesets.md
3展示计划并获得明确批准⛔ 硬性门槛AskUserQuestion
4运行扫描—scripts/run-scans.sh
5后置过滤、合并、生成报告并清理—合并脚本(见下文)

任务执行要求: 调用时,创建 5 个带有 blockedBy 依赖关系的任务(每个步骤阻塞前一步)。第 3 步是硬性门槛——只有在用户明确批准后才能标记为完成。

合并命令(第 5 步):

# run-all
uv run --no-project {baseDir}/scripts/merge_sarif.py "$OUTPUT_DIR/raw" "$OUTPUT_DIR/results/results.sarif" \
  --scans "$OUTPUT_DIR/scans.json"

# important-only, once the JSON post-filter has run over every file in raw/
uv run --no-project {baseDir}/scripts/merge_sarif.py "$OUTPUT_DIR/raw" "$OUTPUT_DIR/results/results.sarif" \
  --important --scans "$OUTPUT_DIR/scans.json"

--scans 会丢弃 .failed 下列出的扫描输出。中途失败的扫描可能仍已写入 .sarif 文件;使用 --important 时,该文件旁没有后置过滤文件,这会导致错误,而不是空过滤结果。不使用此标志时,一次失败的扫描就会使所有正常扫描都无法获得合并结果。被排除的文件会列在标准输出中,因此可以写入报告。

后置过滤器读取的是 SARIF 不包含的元数据,因此无法对合并后的文件重新运行;--important 则会保留 JSON 过滤器保留的发现项,并按 (rule, file, line) 匹配。不使用此标志时,results.sarif 未经过滤,而 JSON 端经过了过滤。

工作流和智能体

组件用途
scripts/run-scans.sh根据已批准的规则集构建每条扫描命令,分批运行,并写入 scans.json

第 4 步是 Bash 调用。没有任何子智能体会执行扫描的任何部分:退出代码和发现项数量会从进程及其写入的 JSON 中读取。

应拒绝的借口

借口错误原因
“用户要求扫描,就等于批准了”原始请求 ≠ 计划获批。展示计划,使用 AskUserQuestion,并等待明确的“是”
“步骤 3 的任务会阻塞流程,直接标记完成吧”谎报任务状态会破坏执行机制。只有获得真实批准后才能标记完成
“我已经知道他们想要什么”主观臆断会导致扫描错误的目录或规则集。展示计划以供确认
“直接使用默认规则集吧”扫描前,用户必须看到并批准确切的规则集
“不问用户就添加额外规则集”未经同意修改已批准的列表会破坏信任
“第三方规则集是可选的”Trail of Bits、0xdea 和 Decurity 能发现官方注册表中没有的漏洞——必须使用
“使用 --config auto”这会发送指标,而且对规则集的控制较少
“我自己运行 semgrep 命令就行”run-scans.sh 会强制使用 --metrics=off、--include 规则和输出目录的 --exclude。手写命令会悄悄漏掉这些选项
“脚本失败了,我直接运行 semgrep 来获取一些结果”返回非零状态意味着扫描未成功。报告这一情况并停止;手动运行的子集会被误认为完整扫描
“有些扫描失败了,但整个流程还是结束了”failed 和 skipped 是 scans.json 的组成部分。报告它们,否则用户会把不完整的扫描误认为扫描无异常
“Pro 太慢了,跳过 --pro 吧”跨文件分析能多发现 250% 的真阳性,值得花时间
“Semgrep 能原生处理 GitHub URL”在 YAML 格式不标准的仓库中,URL 处理会失败;务必先克隆
“清理是可选的”克隆的仓库会污染用户的工作区,并在多次运行后不断累积
“使用 . 或相对路径作为目标”子 Agent 需要绝对路径,避免歧义
“让用户之后再选输出目录”必须在步骤 1 确定输出目录,之后才能创建任何文件

参考索引

文件内容
rulesets.md完整的规则集目录和选择算法
scan-modes.md前置/后置过滤条件和 jq 命令
工作流用途
scan-workflow.md完整的 5 步扫描执行流程
scripts/run-scans.sh步骤 4 调用的扫描运行器

成功标准

  • 已确定输出目录(由用户指定或使用自动递增的默认目录)
  • 所有生成的文件均存储在 $OUTPUT_DIR 中
  • 已检测语言并统计文件数量;已检查 Pro 状态
  • 用户已选择扫描模式(全部运行/仅运行重要项)
  • 规则集包含所有已检测语言对应的第三方规则
  • 用户已明确批准扫描计划(步骤 3 的关卡已通过)
  • run-scans.sh 以状态码 0 退出,并写入了 $OUTPUT_DIR/scans.json
  • scans.json 中的 failed 和 skipped 为空,或已在报告中列出
  • scans.json 中标记为 partial 的扫描为零,或已在报告中列出——这些扫描有部分规则编译失败
  • 每条 semgrep 命令均使用了 --metrics=off
  • 已在步骤 3 的关卡将获批计划写入 $OUTPUT_DIR/rulesets.json,并原样传递给 扫描器
  • scans.json 中的 coveredNothing 为空,或已在报告中列出
  • scans.json 中的 oversized 为空,或已在报告中列出——这些文件超过 --max-target-bytes,没有规则集处理它们
  • 每次扫描的原始输出均存储在 $OUTPUT_DIR/raw/ 中
  • $OUTPUT_DIR/results/ 中存在 results.sarif,且其内容是有效 JSON
  • 仅运行重要项模式:在合并前已应用后置过滤,合并时使用了 --important,未过滤的结果保留在 raw/ 中
  • 已报告结果摘要,并按严重程度和类别分类
  • 已从 $OUTPUT_DIR/repos/ 清理克隆的仓库(如有)

评论

支持 Markdown