关于 codeql
面向代码安全分析的 CodeQL 技能,覆盖多种语言,供需要构建数据库、配置查询并检查结果的开发者使用。它强调数据库质量、项目专属数据扩展和显式查询套件验证,以减少分析遗漏。
主要功能
- 01构建并评估 CodeQL 数据库
- 02为项目 API 创建数据扩展
- 03选择规则集并执行查询
- 04验证查询套件和数据库质量
- 05整理分析产物与报告
适用场景
- 01扫描代码库中的安全问题
- 02复用或创建 CodeQL 数据库
- 03为框架自定义 API 补充数据模型
- 04排查构建质量不足或零结果分析
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trailofbits/ skills --skill codeql安装后在 Claude Code 中输入/codeql确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
agents/openai.yamlassets/trail-of-bits-mark.svgreferences/build-fixes.mddiagnostic-query-templates.mdextension-yaml-format.mdimportant-only-suite.mdlanguage-details.mdmacos-arm64e-workaround.mdperformance-tuning.mdquality-assessment.mdruleset-catalog.mdrun-all-suite.mdsarif-processing.mdthreat-models.mdscripts/build_log.shcheck_db_quality.pyfind_databases.shgenerate_suite.shpyproject.tomltest_build_log.pytest_build_mode_claims.pytest_check_db_quality.pytest_find_databases.pytest_generation_scripts.pytest_script_flags.pytest_section_pointers.pytest_shell_blocks.pytest_suite_templates.pytest_verify_query_suite.pyverify_query_suite.py详细介绍
CodeQL 分析
支持的语言:Python、JavaScript/TypeScript、Go、Java/Kotlin、C/C++、C#、Ruby、Swift。
**技能资源:**参考文件和模板位于 {baseDir}/references/ 和 {baseDir}/workflows/。
核心原则
-
**数据库质量不容妥协。**数据库能够构建并不代表质量合格——缓存的构建不会提取任何内容,却会报告成功。
-
**数据扩展能捕获 CodeQL 遗漏的内容。**Django、Spring 和 Express 项目仍会通过项目专属 API 封装数据库调用、请求解析和 Shell 执行,而 CodeQL 自带的模型未涵盖这些内容。
-
**显式引用套件可防止查询被静默丢弃。**切勿将包名称传给
codeql database analyze——每个包的defaultSuiteFile都会应用隐藏筛选器,可能导致零结果。请始终生成.qls。 -
**零项发现需要调查,而非庆祝。**这可能意味着提取质量差、缺少模型、使用了错误的包,或套件筛选所致。构建后运行
{baseDir}/scripts/check_db_quality.py,确认{baseDir}/scripts/verify_query_suite.py对正在使用的套件返回了零退出码——生成脚本会运行此脚本,因此仅在复用或手动编辑的套件上才需手动调用——并在报告中说明两项检查均已通过。 -
**macOS Apple Silicon 对编译语言需要变通方案。**退出代码 137 表示
arm64e/arm64不匹配,并非构建失败。可尝试 Homebrew arm64 工具或 Rosetta,再考虑退回build-mode=none。 -
**逐步遵循工作流。**每个阶段都是下一阶段的前置条件;跳过质量评估或数据扩展,会让缺口在结果中无从察觉。
每次 Bash 调用都是一个全新的 Shell
每次 Bash 调用之间都不会保留任何内容:变量、数组、从 build_log.sh 引入的函数都不例外。下面每个使用某个值的代码块,都必须在同一代码块中重新设置该值。工作流会指回此处,而不会重复说明;它们说明的是各自位置的具体影响,因为每处的故障表现都不同且不会显式报错:
- 丢失 函数 会导致
run_logged以 127 退出,构建梯级会将其视为失败的方法,并逐级降级至--build-mode=none,整个过程从未调用 CodeQL - 丢失 数组 会使其展开为空,因此用户选择的每个
--threat-model和--model-packs都会被丢弃,但最终报告仍会将它们列为已使用 - 在
set -u下丢失 标量 会因unbound variable而中止代码块
输出目录
所有生成的文件(数据库、构建日志、诊断信息、扩展、结果)都存储在同一个输出目录中。
- 如果用户在提示词中指定了输出目录,请将其用作
OUTPUT_DIR。 - 如果未指定,默认使用
./static_analysis_codeql_1。如果该目录已存在,则依次递增为_2、_3等。
无论哪种情况,都必须在写入任何文件之前使用 mkdir -p 创建目录。
运行此操作前,将 USER_SPECIFIED_DIR 设为用户提示词中的字面路径;若要自动递增,则保持未设置。除此之外,不要在任何地方为它赋值。
# Resolve output directory
USER_SPECIFIED_DIR="${USER_SPECIFIED_DIR:-}" # substitute the user's path here, if any
if [ -n "$USER_SPECIFIED_DIR" ]; then
OUTPUT_DIR="$USER_SPECIFIED_DIR"
else
BASE="static_analysis_codeql"
N=1
while [ -e "${BASE}_${N}" ]; do
N=$((N + 1))
done
OUTPUT_DIR="${BASE}_${N}"
fi
mkdir -p "$OUTPUT_DIR"
输出目录会在任何工作流执行前,于启动时解析一次。所有工作流都会接收 $OUTPUT_DIR,并将其生成的文件存储在该目录中:
$OUTPUT_DIR/
├── rulesets.txt # Selected query packs (logged after Step 3)
├── codeql.db/ # CodeQL database (dir containing codeql-database.yml)
├── build.log # Build log
├── codeql-config.yml # Exclusion config (interpreted languages)
├── diagnostics/ # Diagnostic queries and CSVs
├── extensions/ # Data extension YAMLs
├── raw/ # Unfiltered analysis output
│ ├── results.sarif
│ └── run-all.qls | important-only.qls
└── results/ # Final results (filtered for important-only, copied for run-all)
└── results.sarif
数据库发现
CodeQL 数据库通过其目录中是否存在 codeql-database.yml 标记文件来识别。搜索现有数据库时,始终收集所有匹配项——之前的运行可能留下多个数据库,也可能有适用于不同语言的数据库。
发现命令。 find_databases.sh 每行输出一个数据库路径,并过滤掉失败构建遗留的标记文件。在同一个代码块中构建数组并从中选择——每次 Bash 调用都是一个全新的 shell,因此在此处构建的数组到下一次调用时会变成空数组,最终运行会得出不存在数据库的结论:
# Command substitution, not `done < <(...)`: a process substitution discards the script's
# exit status, so "codeql is not on this shell's PATH" (exit 2) would arrive as an empty
# list and route to "build a new database" with three good ones sitting on disk.
if ! DB_LIST=$("{baseDir}/scripts/find_databases.sh" "${OUTPUT_DIR:-.}" .); then
echo "ERROR: database discovery failed — see the message above" >&2
exit 1
fi
FOUND_DBS=()
while IFS= read -r db; do
[ -n "$db" ] || continue
FOUND_DBS+=("$db")
done <<<"$DB_LIST"
echo "Found ${#FOUND_DBS[@]} existing database(s)"
# The metadata the selection prompt needs, collected here rather than in a block of its
# own: FOUND_DBS is gone by the next Bash call, and a loop over an array that no longer
# exists prints nothing and reports success.
for db in "${FOUND_DBS[@]}"; do
CODEQL_LANG=$(codeql resolve database --format=json -- "$db" 2>/dev/null | jq -r '.languages[0]')
CREATED=$(grep '^creationMetadata:' -A5 "$db/codeql-database.yml" 2>/dev/null | grep 'creationTime' | awk '{print $2}')
echo "$db — language: $CODEQL_LANG, created: $CREATED"
done
切勿假设数据库名为 codeql.db——应通过其标记文件来发现数据库。
**找到多个数据库时:**使用 AskUserQuestion,让用户根据上方打印的语言和创建时间,选择要使用的数据库或构建新数据库。AskUserQuestion 最多接受四个选项,因此如果数据库数量超过四个,应提供最近的三个数据库和“构建新数据库”,并在提示文本中列出其余数据库。如果用户在提示中明确说明要使用哪个数据库或要构建新数据库,则跳过 AskUserQuestion。
快速开始
对于常见情况(“扫描此代码库以查找漏洞”):
# Verify CodeQL is installed. Stop here if it is not — every later command fails with
# a less informative error, and the run wastes a build cycle before saying why.
if ! command -v codeql >/dev/null 2>&1; then
echo "ERROR: codeql not found on PATH. Install it with one of:" >&2
echo " gh extension install github/gh-codeql # then: gh codeql install-stub" >&2
echo " brew install --cask codeql" >&2
echo " https://github.com/github/codeql-action/releases (codeql-bundle)" >&2
exit 1
fi
# jq parses `codeql resolve database --format=json` in the very next step. Without it
# CODEQL_LANG comes back empty and the run continues against the wrong language.
if ! command -v jq >/dev/null 2>&1; then
echo "ERROR: jq not found on PATH (brew install jq / apt install jq)" >&2
exit 1
fi
# uv runs both guard scripts and both suite generators. Check it here rather than at
# suite generation, which is after the build — otherwise a machine without uv spends
# the whole build before failing.
if ! command -v uv >/dev/null 2>&1; then
echo "ERROR: uv not found on PATH (https://docs.astral.sh/uv/getting-started/)" >&2
exit 1
fi
codeql --version
然后使用上文输出目录中的代码块解析 OUTPUT_DIR——它会遵循用户指定的目录,而直接自动递增则不会。
然后使用以下工作流执行完整流程:构建数据库 → 创建数据扩展 → 运行分析。
应避免的错误理由
这些捷径会导致漏报。不要接受:
- “security-extended 就够了” - 这是基准方案。始终检查该语言是否有 Trail of Bits 包和 Community Packs。它们能发现
security-extended完全遗漏的类别。 - “security-and-quality 是范围最广的套件” -
security-and-quality会排除所有experimental/查询路径。对于运行全部模式,同时导入security-and-quality和security-experimental。根据语言不同,两者之间相差 1–52 个查询。 - “数据库构建成功,所以没问题” - 数据库构建成功并不意味着提取效果良好。始终进行质量评估,并核对文件数量与预期源文件数量。
- “标准框架不需要数据扩展” - 即使是 Django/Spring 应用也有 CodeQL 未建模的自定义包装器。跳过扩展意味着漏掉漏洞。
- “对于编译型语言,build-mode=none 没问题” - 这会导致分析严重不完整。仅在绝对无计可施时使用。在 macOS 上,先尝试 arm64 工具链变通方案或 Rosetta。
- “在 macOS 上构建失败,那就用 build-mode=none” - 退出代码 137 是由
arm64e/arm64不匹配导致的,并非根本性的构建失败。请参阅 macos-arm64e-workaround.md。 - “没有发现结果就说明代码安全” - 运行
check_db_quality.py和verify_query_suite.py,并报告检查通过。没有这些检查,零发现与未提取任何内容的数据库会产生相同的输出。 - “我就运行默认套件” / “我直接传入包名就行” - 每个包的
defaultSuiteFile都会应用隐藏过滤条件,可能导致结果为零。始终使用明确的套件引用。 - “我把文件放在当前目录就行” - 所有生成的文件都必须放在
$OUTPUT_DIR中。将文件散落在工作目录中会导致无法清理,还可能覆盖之前的运行结果。 - “直接用我找到的第一个数据库就行” - 不同语言或之前的运行可能会产生多个数据库。找到多个数据库时,向用户展示所有选项。只有在用户已指定要使用哪个数据库时,才跳过提示。
- “用户说了‘扫描’,这就表示他们希望我选择数据库” - “扫描”并不等于选择数据库。如果存在多个数据库,而用户没有指定其中一个,就应询问。
工作流选择
此技能有三个工作流。选择工作流后,请按步骤执行,不要跳过任何阶段。
这些运行耗时较长。数据库构建有四种备用方法,因此请使用任务工具跟踪进度。根据运行情况,决定哪些步骤值得跟踪。
| 工作流 | 用途 |
|---|---|
| build-database | 依次使用构建方法创建 CodeQL 数据库 |
| create-data-extensions | 检测或生成项目 API 的数据扩展模型 |
| run-analysis | 选择规则集、执行查询并处理结果 |
无人值守构建
此插件附带 /static-analysis:codeql-build,可端到端执行 build-database 的步骤:检测语言和工具链,按顺序尝试各方法,并在每个阶段之间应用 build-fixes.md 中的修复,然后执行质量门禁。
/static-analysis:codeql-build {"target": "/abs/path", "lang": "cpp"}
此过程不会提问。如果所有方法都失败,或者数据库虽已构建但低于质量阈值,就会返回状态 — no-method-succeeded 和 built-below-threshold — 供你在此处处理,因为剩余的提取器错误是否仅出现在无需分析的代码中,需要人为判断,运行本身无法决定。
如果构建过程漫长且不确定,而你希望自动推进直到得出结论,请使用此方式。如果你想决定尝试哪种方法,或者需要在构建失败时即时分析原因,请手动执行 build-database.md。
自动检测逻辑
如果用户明确指定要执行的操作(例如,“构建数据库”、“对 ./my-db 运行分析”),则直接执行相应工作流。如果用户的提示已清楚表明其意图,请勿调用 AskUserQuestion 来选择数据库 — 例如,“构建一个新数据库”、“分析 static_analysis_codeql_2 中的 codeql 数据库”、“从头开始运行完整扫描”。
对于“测试”、“扫描”、“分析”或类似请求的默认流程: 使用上文数据库发现中的命令查找现有数据库,然后再决定。
| 条件 | 操作 |
|---|---|
| 未找到数据库 | 确定新的 $OUTPUT_DIR,依次执行构建 → 扩展 → 分析(完整流程) |
| 找到一个数据库 | 使用 AskUserQuestion:复用该数据库还是新建? |
| 找到多个数据库 | 使用 AskUserQuestion,最多提供四个选项 — 参见数据库发现 |
| 用户已明确说明意图 | 跳过 AskUserQuestion,直接按用户指示操作 |
数据库选择提示
如果找到现有数据库,且用户未明确指定要使用哪个数据库,请通过 AskUserQuestion 展示这些数据库,标题为“现有 CodeQL 数据库”。每个选项都要包含上文收集到的路径、语言和创建时间 — ./static_analysis_codeql_1/codeql.db (language: python, created: 2026-02-24) — 最后一个选项设为“构建新数据库”。
选择后:
- 如果用户选择现有数据库: 将
$OUTPUT_DIR设为其父目录(或包含该数据库的目录),将$DB_NAME设为所选路径,然后继续执行扩展 → 分析。 - 如果用户选择“构建新数据库”: 确定新的
$OUTPUT_DIR,依次执行构建 → 扩展 → 分析。
通用决策提示
如果提示中未明确数据库或工作流,请通过 AskUserQuestion 提供四种工作流 — 完整扫描(推荐)、构建数据库、创建数据扩展、运行分析 — 并列出找到的数据库和确定的 $OUTPUT_DIR。
参考索引
| 文件 | 内容 |
|---|---|
| 脚本 | |
| scripts/verify_query_suite.py | 当解析出的查询数为零时使套件失败。生成脚本会运行它;仅在重用或手动编辑套件时手动调用 |
| scripts/check_db_quality.py | 当数据库没有可分析的源代码时使其失败。每次构建后运行 |
| scripts/build_log.sh | log_step/run_logged 辅助函数;在任何构建步骤前先加载 |
| scripts/find_databases.sh | 每行输出一个 codeql resolve database 可接受的数据库。在读取它的代码块中据此构建数组 |
| scripts/generate_suite.sh | 写入 run-all 或 important-only .qls,并验证其解析出的查询数非零 |
| 参考资料 — 三种工作流列于工作流选择 | |
| references/macos-arm64e-workaround.md | Apple Silicon 构建跟踪的解决方法 |
| references/build-fixes.md | 构建失败修复目录 |
| references/quality-assessment.md | 数据库质量指标与改进 |
| references/extension-yaml-format.md | 数据扩展 YAML 列定义和示例 |
| references/sarif-processing.md | 处理 SARIF 输出的 jq 命令 |
| references/diagnostic-query-templates.md | 用于枚举源/汇的 QL 查询 |
| references/important-only-suite.md | 仅重要项套件模板与生成 |
| references/run-all-suite.md | 全部运行套件模板 |
| references/ruleset-catalog.md | 按语言列出的可用查询包 |
| references/threat-models.md | 威胁模型配置 |
| references/language-details.md | 特定语言的构建和提取详情 |
| references/performance-tuning.md | 内存、线程和超时配置 |
成功标准
完整的 CodeQL 分析运行应满足以下条件:
- 已解析输出目录(由用户指定或使用自动递增的默认值)
- 所有生成的文件均存储在
$OUTPUT_DIR中 - 已构建数据库(通过
codeql-database.yml标记发现),且{baseDir}/scripts/check_db_quality.py的退出码为零 - 已评估数据扩展 — 要么创建在
$OUTPUT_DIR/extensions/中,要么明确说明跳过的理由 - 使用明确的套件引用(而非默认包套件)运行分析,且
{baseDir}/scripts/verify_query_suite.py对该套件的退出码为零 - 已使用或明确排除所有已安装的查询包(官方 + Trail of Bits + Community)
- 已将选定的查询包记录到
$OUTPUT_DIR/rulesets.txt - 未经过滤的结果已保存在
$OUTPUT_DIR/raw/results.sarif - 最终结果位于
$OUTPUT_DIR/results/results.sarif中(仅重要项模式下经过过滤;全部运行模式下直接复制) - 已调查零发现结果(数据库质量、模型覆盖范围、套件选择)
- 构建日志已保存在
$OUTPUT_DIR/build.log,其中包含所有命令、修复和质量评估