CodeQL 使用札记
CodeQL 是一个语义代码分析引擎,它可以扫描发现代码库中的漏洞;通过对项目源码(C/C++、C#、golang、java、JavaScript、typescript、python)进行完整编译,并在此过程中把项目源码文件的所有相关信息(调用关系、语法语义、语法树)存在数据库中,然后编写 QL 代码或使用自带的 QL 规则查询该数据库来发现安全漏洞。
官方文档:
快速使用命令
整个工作流程主要分为两步:
- 提取创建数据库
- 编写 QL 语句进行查询
编译代码,生成数据库
codeql database create <database-folder> --language=cpp --command=<prefix command>
# 方式1
codeql database create webgoat-ql -l java
# 方式2
codeql database create xxx-database --language="java" --command="mvn clean install --file pom.xml" --source-root=文件目录
# 方式3
codeql database create test --language=java --command="mvn clean compile --file pom.xml -Dmaven.test.skip=true" --source-root=../micro_service_seclab/
codeql database create支持--overwrite标志
- 官方文档描述:
--no-overwrite
[Advanced] If the database already exists, delete it and
proceed with this command instead of failing.
If the directory exists, but it does not look like a database,
an error will be thrown.
- 标准处理方式:当数据库已存在时,CodeQL 会拒绝创建并提示使用
--overwrite标志
对于 Java 语言的 Maven 项目使用如下命令即可:
codeql database create --language java --source-root . --command 'mvn clean install -f "pom.xml" -U -B -V -e -Dfindbugs.skip -Dcheckstyle.skip -Dpmd.skip=true -Dspotbugs.skip -Denforcer.skip -Dmaven.javadoc.skip -DskipTests -Dmaven.test.skip.exec -Dlicense.skip=true -Drat.skip=true -Dspotless.check.skip=true' xxx-db
参数说明:
database create代表创建数据库--language:指定源码语言--source-root:指定源码路径--command:指定编译命令,java 的 maven 项目都可以使用上述指定的编译命令xxx-db:生成的数据库的文件名,名称可任意
如果省略
--command参数,则 codeQL 会自动检测并使用自己的工具来构建。但还是强烈推荐使用自己自定义的参数,尤其是大项目时。
生成 Java 项目的数据库时,之所以使用手动输入编译命令的方式,是因为当项目使用 Maven Wrapper 时,自动编译脚本会使用 mvnw 命令进行编译,此时会拉取相应版本的 maven 安装包,这个过程需要很长的时间,而且意义不大,因此使用上述命令是最高效的方式。
在较新的 codeql 版本中,codeql 支持在不构建代码的情况下生成数据库,实测对于源码项目,这种无构建模式形成数据库非常缓慢,效果聊胜于无。 可能对于 jar、war 等格式的二进制包的构建效果会比较好,待进一步测试和确认
无构建模式的示例命令:
codeql database create db-name --language=java --source-root=./sources --build-mode=none
分析数据库,生成结果
使用如下命令查询第三步生成的数据库:
codeql database analyze xxx-db $CODEQL_HOME/qlpacks/codeql/$LANGUAGE-queries/0.8.13/codeql-suites/$LANGUAGE-code-scanning.qls --format sarifv2.1.0 --output xxx.sarif
参数说明:
database analyze代表分析数据库xxx-db:上一步生成的数据库的路径$CODEQL_HOME为 codeql 安装目录0.7.13为下载的 codeql 的规则的版本号,需要注意修改,确保路径正确且有效--format sarifv2.1.0:代表生成的扫描结果为 sarif 格式,该格式的文件可通过 vscode 的插件打开--output:指定扫描结果的输出路径
codeql database analyze命令 不支持--overwrite标志
- 原因:
analyze命令不创建数据库,只是分析现有数据库,因此不需要--overwrite标志- 相关选项:
--no-rerun- 重新评估已有 BQRS 结果的查询
关于官方规则
codeql 官方规则中,存在两组安全规则
D:\00PackageManager\codeqlRules\java\ql\src\experimental\Security\CWE\D:\00PackageManager\codeqlRules\java\ql\src\Security\CWE\
这两组规则的主要区别在于:experimental 目录下的规则是实验性质的,而 Security 目录下的规则是正式且稳定的。
批量查询
codeql database run-queries --ram=16384 --threads=12 XNU-database --min-disk-free=1024 -v D:\codeql-starter\ql\java\ql\src\codeql-suites\java-security-extended.qls
codeql database run-queries --ram=16384 --threads=12 .\Log4jDB\ --min-disk-free=1024 -v .\codeql-main\java\ql\src\codeql-suites\java-security-extended.qls
Cli 性能控制参数
--ram=16384 --threads=12 --min-disk-free=1024
用于控制 RAM 使用情况的选项
-M, --ram=<MB>:查询计算器将努力将其总内存占用情况保持在此值以下。 (但对于大型数据库而言,阈值可能会被文件支持的内存图破坏,如果出现内存压力,可以交换到磁盘)。该值应至少为 2048 MB;较小的值将以透明方式向上舍入。-j, --threads=<num>:使用如此多的线程来评估查询。默认值为 1。 可以传递 0 以在计算机上对每个核心都使用一个线程,也可以传递 -N 以将 N 个核心保留为未使用状态(仍至少使用一个线程的情况除外) 。--min-disk-free=<MB>:[高级] 设置文件系统上的目标可用空间量。如果未提供--max-disk-cache,当文件系统上的可用空间低于此值时,计算器便会努力减少磁盘缓存使用量。
查询规则集
java 规则集
codeql-suites
- java-code-scanning.qls
- java-lgtm-full.qls
- java-lgtm.qls
- java-security-and-quality.qls
- java-security-experimental.qls
- java-security-extended.qls
环境准备
CodeQL 本身包含两部分:解析引擎 +SDK。
- 解析引擎用来解析我们编写的规则,虽然不开源,但是我们可以直接在官网下载二进制文件直接使用;
- SDK 完全开源,里面包含大部分现成的漏洞规则,我们也可以利用其编写自定义规则。
安装:
- codeql cli
- codeql 查询规则
- vscode - SARIF Viewer - CodeQL
ql 库(SDK)路径说明
- 两个目录必须放置到同级,因为 codeql-cli 把同层目录作为查找路径,调用更方便
快速部署
# 下载codeql.zip
wget https://github.com/github/codeql-cli-binaries/releases/latest/download/codeql.zip
# 解压
unzip codeql.zip
# 将codeql添加至path中
echo "export PATH=\$PATH:/path/to/codeql" >> ~/.zshrc
source ~/.zshrc
此外,还可以使用包管理器进行安装
# windows
scoop install codeql
choco install codeql
# macos
brew install codeql
SARIF Viewer 使用避坑
安装 SARIF Viewer 插件之后,使用 vscode 打开 sarif 文件进行预览分析时,会提示文件找不到,有两种解决办法:
- 先用 vscode 打开 sarif 文件对应的源码目录,然后打开 sarif 文件即可正常预览分析
- 修改 sarif 文件,在 runs 字段中添加如下属性
"originalUriBaseIds" : {
"%SRCROOT%" : {
"uri" : "file:///tmp/java-sec-code/"
}
},
工作区配置
Codeql 除了直接使用 codeql cli +codeql 库 之外,GitHub 官方还提供了 vs code 工作区来方便使用
该工作区内含了 QL 库,因此一定要使用递归方式来下拉工作区代码
vscode 的工作区缓存数据库格式为
.vscdb,位置默认在 vscode 的安装目录下,其为 SQLite 数据库,默认未加密;
git clone --recursive git@github.com:github/vscode-codeql-starter.git
内网使用环境配置
目录规范
-
创建工作目录
mkdir F:\Codes\ mkdir F:\Codes\00-CodeQL-source\ # 源代码存放目录 mkdir F:\Codes\00-CodeQL-result\ # 扫描结果存放目录 mkdir F:\Codes\00-CodeQL-database\ # CodeQL 数据库存放目录 -
使用 GitHub Actions 构建一个完整的 scoop 环境,然后打包归档至内网进行重建,GitHub Actions 可以顺带拷贝一份 codeql 的规则
-
下载一份免安装的Oracle jdk 8到主机目录
-
修改和配置 maven 和 idea-ultimate 的 maven 配置文件 (
setting.xml)- 本地 .m2 目录:
Local repository目录 - 内网的 maven 源
- 本地 .m2 目录:
-
安装和激活 idea-ultimate
-
配置 vs-code,下载 VSIX 格式插件安装文件,拷贝到内网,然后在 VSCode 的 more actions 中选择【从 VSIX 文件安装】
- CodeQL for VSCode
- sarif viewer
基础环境快速配置
Windows 环境下,可以使用 scoop 来完成 codeql 使用环境的构建:
scoop install liberica-full-jdk liberica11-full-jdk liberica17-full-jdk liberica8-full-jdk
scoop install maven gradle chsrc
scoop install codeql
统一 IDEA 自动的 maven 配置
IDEA 自带 Maven,在 IDEA 安装目录下 plugins\maven\lib\maven3,如果需要换 IDEA 中自带的 Maven 和配置,可以按 Ctrl + Alt + S 打开当前 IDEA 项目的设置,找到 Build, Execution, Deployment -> Build Tools -> Maven,修改:
- 将
Maven home path替换成刚解压的位置D:\Maven\apache-maven-3.9.8\conf\settings.xml。 - 将
Local repository设置成D:\Maven\repository,这个目录不存在会自动创建。 - 或者在 Maven 配置文件
settings.xml中的<localRepository>/path/to/local/repo</localRepository>部分指定仓库路径,后续 maven 会读取这个仓库路径自动配置 Local repository
GitHub Action 打包 Scoop 归档更新 Codeql 环境事项
通过 GitHub action 打包的 codeql 离线归档进行更新时,先删除原始的 codeql 规则和 codeql vs 工作区文件夹
rm D:\00PackageManager\vscode-codeql-starter
rm D:\00PackageManager\CodeqlRules
批量值守思路
基本思路:
- 先判断 source 文件夹是否存在
- 不存在:执行 git clone
- 存在:进入文件夹,执行
git fetch --all
- 判断代码仓库是否存在更新
- 存在更新:进入文件夹,执行
git fetch --all和 codeql 的数据库的创建和扫描 - 不存在更新:跳过这个数据库
- 存在更新:进入文件夹,执行
- codeql 数据库的创建,使用两个 jdk 版本进行编译
- 使用 jdk 8 和 jdk 21 分别编译
- 首先使用 jdk 8 进行 maven 的编译,编译失败切换到 jdk 21
- 编译 jdk 版本则使用临时环境变量进行制定
批量获取仓库地址
懒人办法:
在 chrome 系浏览器中,安装 id 为 cljbfnedccphacfneigoegkiieckjndh,名称为 Easy Scraper的插件
内网环境下插件流程:
- 下载插件的离线安装包
- 下载 edge 或者 chrome 的管理模板并添加到组策略中,然后在组策略中设置如下两项配置项
- 启用【配置扩展程序安装许可名单】,并添加扩展插件的 id
- 禁用【禁止安装外部扩展程序】
- 解压离线安装包,然后将 crx 安装文件拖动到浏览器的插件管理页面
- 打开 git 仓库页面并登录,然后使用【Easy Scraper】进行爬取
- 处理扫描结果
- 反选仓库描述为废弃的仓库
- 然后使用 Excel 拼接语句完成后续批量命令的整理
Chrome 管理模板及组策略配置过程
相关示例截图为 edge 浏览器配置截图,可对照修改
- 找到 Chrome 管理模板的下载地址,下载管理模板到本地
- 将下载的管理模板进行解压,确保能访问
\windows\adm\zh-CN子目录 - 按【Win+R】键打开运行,输入【gpedit.msc】确定,进入本地组策略编辑器。

- 点击【计算机配置 →管理模板】 ,右键菜单【添加/删除模板 →添加】

- 选择解压文件夹中的【windows/adm/zh-CN/msedge.adm】文件,将我们刚才找到的文件添加进去

- 添加完成后,在管理模版列表中会出现【经典管理模块 ADM】

- 修改如下两个配置项
- 启用【配置扩展程序安装许可名单】,并添加扩展插件的 id
- 禁用【禁止安装外部扩展程序】
LLM 分析 Codeql 输出格式笔记
在结合 LLM 进行漏洞分析和确认时,推荐使用 SARIF(Static Analysis Results Interchange Format)格式。以下是具体分析和理由:
1. 为什么选择 SARIF?
-
结构化 & 标准化 SARIF 是专为静态分析工具设计的标准化 JSON 格式,包含漏洞的完整上下文,例如:
- 代码位置(文件路径、行号、列号)
- 漏洞描述与规则 ID(如
cpp/sql-injection) - 严重性等级(Critical/High/Medium/Low)
- 代码片段、调用堆栈、数据流路径(通过 CodeQL 的
@kind path-problem查询生成)。
-
支持多维度信息 可嵌入代码片段、数据流路径(展示漏洞触发路径),这对 LLM 理解漏洞成因至关重要。例如:
"locations": [{ "physicalLocation": { "artifactLocation": { "uri": "src/main.cpp" }, "region": { "startLine": 42, "startColumn": 5 } }, "message": { "text": "Potential SQL injection risk from user input." } }] -
便于自动化处理 LLM 可直接解析 JSON 中的关键字段,生成自然语言报告或验证漏洞有效性。例如:
import json with open("results.sarif") as f: data = json.load(f) for run in data["runs"]: for result in run["results"]: print(f"漏洞: {result['message']['text']}, 位置: {result['locations'][0]['physicalLocation']}") -
生态兼容性 GitHub 高级安全、VS Code 插件等均支持 SARIF,便于集成到 CI/CD 和开发流程中。
2. 其他格式的局限性
- CSV:扁平化结构,缺乏层级关系和代码上下文,LLM 需额外推断漏洞路径。
- BQRS(Bileto):需通过 CodeQL CLI 转换后才能阅读,非标准格式,处理成本高。
- SARIF-Latest:与 SARIF 类似,但可能因版本更新导致解析不稳定。
3. 推荐工作流程
-
生成 SARIF 报告
codeql database analyze --format=sarif-latest --output=results.sarif my-db -
解析并输入 LLM 提取 SARIF 中的关键信息(如代码片段、漏洞描述),构建 LLM 提示词:
请分析以下漏洞: - 文件: src/main.cpp:42 - 描述: 用户输入未经过滤,可能导致 SQL 注入。 - 代码: `query = "SELECT * FROM users WHERE id = " + user_input;` 这是否为误报?如何修复? -
LLM 输出优化建议
模型可返回:
- 漏洞确认/误报判断
- 修复建议(如参数化查询)
- 风险等级评估
4. 附加技巧
- 过滤高置信度结果:结合 CodeQL 的
@precision标签,优先提交高置信度漏洞给 LLM。 - 交互式分析:让 LLM 追问更多上下文(如“请展示数据流从用户输入到敏感函数的完整路径”),动态补充信息。
总结:SARIF 格式凭借其结构化、高信息密度和标准化支持,是连接 CodeQL 与 LLM 的最佳桥梁,能有效提升漏洞分析的准确性和自动化程度。
编写 QL 规则查询
在 ~/codeql/ql/java/ql/examples/test.ql 中编写测试代码,因为 examples 目录下有 qlpack.yml 就不需要再新建了。
codeQL 规则有包结构/目录结构要求(qlpack.yml 定义一个 package),才能正常编译、执行。
参考:https://codeql.github.com/docs/codeql-cli/using-custom-queries-with-the-codeql-cli/
编译 Ql 文件
在批量构建和查询时,建议增加此步骤
一般情况下,我们在执行一遍 codeql database analyze 命令后,便会将 ql 的编译结果写入缓存,因此个人使用时无需使用提前编译的功能,但是在 CI/CD 流程中使用 CodeQL 进行自动化扫描时,则需要提前编译好,因为这种场景每次运行 codeql 都是在一个新的环境,因此我们就需要提前将 ql 编译好,再将 codeql 安装包打包,这样会极大提升扫描速度。
提前编译 ql 文件的命令如下:
codeql query compile -- $CODEQL_HOME/qlpacks/codeql/$LANGUAGE-queries/0.8.13/codeql-suites/$LANGUAGE-code-scanning.qls
例如,需要编译 java 的 java-code-scanning.qls 查询套件,就可以使用如下命令:
codeql query compile -- $CODEQL_HOME/qlpacks/codeql/java-queries/0.8.13/codeql-suites/java-code-scanning.qls
创建自定义查询套件
codeql 安装目录下的 qlpacks 目录,存放了 codeql 所有的规则
以 Java 为例,最常用的查询套件就是 java-code-scanning.qls,其内容如下:
- description: Standard Code Scanning queries for Java
- queries: .
- apply: code-scanning-selectors.yml
from: codeql/suite-helpers
发现其引用了 $CODEQL_HOME/qlpacks/codeql/suite-helpers/0.7.13 目录下的 code-scanning-selectors.yml 文件,其内容如下
- description: Selectors for selecting the Code-Scanning-relevant queries for a language
- include: # include表示该查询套件包含如下查询
kind: # kind属性表示如何展示查询分析的结果
- problem # 仅展示漏洞sink点
- path-problem # 展示漏洞source -> sink完整的数据流
- alert # 该属性不常用
- path-alert # 该属性不常用
precision: # precision属性表示该查询规则的精准度,包括低、中、高、超高四种级别
- high
- very-high
problem.severity: # problem.severity属性表示该查询结果的危害程度
- error
- warning
tags contain: # tags属性表示该查询规则的标签,主要目的方便被搜索和引用
- security
- include:
kind:
- diagnostic # 分析数据库时的故障报告
- include:
kind:
- metric # 输出源码的一些摘要指标,如代码行数,引用的依赖库等
tags contain:
- summary
- exclude:
deprecated: //
- exclude: # exclude表示该查询套件会排除如下查询
query path:
- /^experimental\/.*/ # 排除实验性的查询规则
- Metrics/Summaries/FrameworkCoverage.ql
- /Diagnostics/Internal/.*/
- exclude: # 排除tags属性中包含modeleditor和modelgenerator的查询规则
tags contain:
- modeleditor
- modelgenerator
前面提到的 $LANGUAGE-code-scanning.qls 查询套件,默认会扫描所有的安全规则,如果我们只想扫描我们关心的高危漏洞,那就可以新建一个查询套件。当使用如下扫描套件时,仅会扫描如下 id 对应的规则:
- description: rce漏洞扫描规则
- include:
id:
- java/path-injection
- java/zipslip
- java/jndi-injection
- java/command-line-injection
- java/sql-injection
- java/mybatis-xml-sql-injection
- java/mybatis-annotation-sql-injection
- java/spel-expression-injection
- java/unsafe-deserialization
- java/ognl-injection
- java/unsafe-eval
- java/jshell-injection
- java/jython-injection
- java/server-side-template-injection
- java/mvel-expression-injection
- java/groovy-injection
- java/jexl-expression-injection
这些 id 值可以从如下目录中获取:
$CODEQL_HOME/qlpacks/codeql/$LANGUAGE-queries/0.8.13/Security/CWE
该目录中以 CWE 漏洞类型,将规则进行了分类,如 CWE-022 目录下全部为路径操作相关的漏洞规则,其中 TaintedPathLocal.ql 规则用于查询路径穿越漏洞,其 id 值为 java/path-injection
个人测试效果比较好的规则
-
java\ql\src\experimental\Security\CWE\CWE-089 -
spel 表达式注入:CWE-094
-
基于 mybatis 的 SQL 注入查询: CWE-089
大批量查询下的性能优化思路
- 预编译查询规则
- 创建 CodeQL CLI 数据库捆绑包
此示例
database bundle命令需要 CodeQL CLI 版本 2.17.6 或更高版本。
codeql database bundle --output=codeql-debug-artifacts.zip --include-diagnostics --include-logs --include-results -- <dir>
为已编译语言创建数据库
指定生成命令
以下示例旨在让你了解可为编译语言指定的一些生成命令。
--command选项接受单个参数,如果需要使用多个命令,请多次指定--command。 如果需要传递子命令和选项,则需要引用整个参数才能正确解释。
- 使用 Gradle 生成的 Java 项目:
# Use `--no-daemon` because a build delegated to an existing daemon cannot be detected by CodeQL.
# To ensure isolated builds without caching, add `--no-build-cache` on persistent machines.
codeql database create java-database --language=java-kotlin --command='gradle --no-daemon clean test'
- 使用 Maven 生成的 Java 项目:
codeql database create java-database --language=java-kotlin --command='mvn clean install'
- 使用 Ant 生成的 Java 项目:
codeql database create java-database --language=java-kotlin --command='ant -f build.xml'
关于使用 CodeQL CLI 分析数据库
正在运行 codeql database analyze
可以通过运行以下命令来分析数据库:
codeql database analyze <database> --format=<format> --output=<output> <query-specifiers>...
必须指定
<database>、--format和--output。 可以指定其他选项,具体取决于要执行的分析。
| 选项 | 必选 | 使用情况 |
|---|---|---|
--sarif-add-baseline-file-info | × | 推荐。 用于将文件覆盖率信息提交到 工具状态页。 有关详细信息,请参阅“关于代码扫描的工具状态页”。 |
| —threads | × | 如果想使用多个线程来运行查询,请使用此选项。 默认值是 1。 可以指定更多线程来加快查询执行速度。 要将线程数设置为逻辑处理器数,请指定 0。 |
| —verbose | × | 用于从数据库创建过程中获取有关分析过程和诊断数据的更多详细信息。 |
将文件覆盖率信息添加到结果以供监视
可以选择将文件覆盖率信息提交到 GitHub,以供显示在 code scanning 的 工具状态页 上。 有关文件覆盖率信息的详细信息,请参阅“关于代码扫描的工具状态页”。
若要在 code scanning 结果中包含文件覆盖率信息,请将 --sarif-add-baseline-file-info 标志添加到 CI 系统中的 codeql database analyze 调用,例如:
$ codeql database analyze /codeql-dbs/example-repo \
javascript-code-scanning.qls --sarif-category=javascript-typescript \
--sarif-add-baseline-file-info \ --format=sarif-latest \
--output=/temp/example-repo-js.sarif
报错解决
Error Running Query: Internal Error
报错:
Error running query: Internal error. (codeQLQueries.runLocalQueryFromQueriesPanel) Error: Error running query: Internal error.
报错原因:
电脑内存不足
Git 报错 schannel: next InitializeSecurityContext failed
最近在使用 git 拉取代码和提交代码时报错:
schannel: next InitializeSecurityContext failed: Unknown error
查阅资料,导致的原因可能是使用代理导致了 git 的连接模式改变。
解决方式:
打开 cmd 窗口,执行下面命令把 URL 模式从 HTTPS 改为 SSH 即可:
git config --system http.sslbackend openssl
参考资料
- CodeQL开箱即用的便捷使用教程
- codeql初体验
- 在 CodeQL CLI 中使用自定义查询
- IDEA 安装&配置
- Error running query: Internal error. (codeQLQueries.runLocalQueryFromQueriesPanel) Error: Error running query: Internal error.General issue
- CodeQL for VSCode 搭建流程
- fatal: unable to access ‘https://github.com/xxx’: OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443
- CodeQL 基础 - Geekby’s Blog
- 批量运营CodeQL Cli扫描结果(简易版)