关于 irify-sast
irify-sast 是面向编码 Agent 的静态分析技能,使用 IRify 的 SSA 编译器和 SyntaxFlow 查询跨文件数据流。它通过 yaklang MCP 服务支持查询驱动的安全分析与增量重新编译。
主要功能
- 01基于 SSA 的跨文件分析
- 02SyntaxFlow 查询指导
- 03增量编译流程
- 04按用户意图构造安全查询
- 05查询错误重试指导
适用场景
- 01追踪代码中的用户输入
- 02查找指定的漏洞路径
- 03定位调用方和数据去向
- 04代码变更后更新分析
MCP 相关
需要配置 yaklang MCP 服务,并使用 `yak mcp -t ssa` 命令。该技能通过其 SSA 编译与查询能力进行分析。
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ yaklang/ irify-sast-skill --skill irify-sast安装后在 Claude Code 中输入/irify-sast确认已加载。
附带文件nativecall-reference.mdsyntaxflow-examples.md
详细介绍
IRify SAST
由 IRify 的 SSA 编译器和 SyntaxFlow 查询引擎驱动的深度静态分析技能。
前置条件
此技能需要 yaklang MCP 服务。请在 Agent 的 MCP 设置中进行配置:
# Codex: ~/.codex/config.toml
[mcp_servers.yaklang-ssa]
command = "yak"
args = ["mcp", "-t", "ssa"]
// Claude Code / Cursor / others
{ "command": "yak", "args": ["mcp", "-t", "ssa"] }
工作流:引擎优先(sf → read → rg)
重要:始终遵循引擎优先漏斗模型。SSA 引擎可以同时查看所有文件中的跨过程数据流,而 grep 做不到。查询前不要使用 grep/rg 构建“候选文件池”。应先让引擎充当雷达。
步骤 1:编译(每个项目一次,自动缓存)
ssa_compile(target="/path/to/project", language="java", program_name="MyProject")
→ full compilation, returns program_name
自动缓存:如果程序已编译且源文件未更改,引擎会立即返回 [Cache Hit],无需重新编译。始终提供 program_name 以启用缓存。
步骤 2:查询 — 使用 SyntaxFlow 作为全局雷达
直接针对已编译的 IR 编写并执行 SyntaxFlow 规则。不要先用 grep 预扫描来查找候选项。
ssa_query(program_name="MyProject", rule="<SyntaxFlow rule>")
引擎会在内存中遍历整个 SSA 图,跨越所有文件边界。一次查询即可覆盖数十条 grep 命令的工作量,并且在数据流分析中不会产生误报。
步骤 3:读取 — 使用 Read 作为显微镜
ssa_query 返回具体文件路径和行号后,使用 Read 查看周边上下文(±20 行)。确认命中的是实际业务代码,而不是死代码或测试代码。
步骤 4:Grep — 仅对非代码文件使用 Grep/Glob
仅对 SSA 引擎无法处理的内容使用 Grep/Glob:
- 配置文件(
.yml、.xml、.properties、logback.xml) - 静态资源、模板、构建脚本
- 已知确切字符串时,快速查找名称/路径
绝不要使用 Grep 搜索源代码中的数据流模式——这正是 ssa_query 的用途。
增量编译(代码变更时)
ssa_compile(target="/path/to/project", language="java", base_program_name="MyProject")
→ only changed files recompiled, ProgramOverLay merges base + diff layers
→ returns NEW program_name for subsequent queries
重要:增量编译时使用 base_program_name。re_compile=true 会执行完整重新编译并丢弃所有数据——仅在需要彻底重新开始时使用。
查询自愈(语法错误时自动重试)
当 ssa_query 返回 SyntaxFlow 解析错误时:
- 不要向用户道歉或寻求帮助
- 阅读错误信息——其中包含准确的解析错误位置和预期标记
- 根据错误修复 SyntaxFlow 规则
- 使用修正后的规则重新调用
ssa_query - 最多重复 3 次,然后再报告失败
- 如果所有重试均失败,向用户展示:原始规则、每次尝试的修正内容以及最终错误
关键:遵循用户意图
除非用户明确要求检测漏洞,否则不要自动构建源→汇漏洞规则。
- 用户要求“查找用户输入” → 编写仅源规则,列出所有输入端点
- 用户要求“查找 SQL 注入” → 编写源→汇污点规则
- 用户要求“这个值会流向哪里” → 编写正向追踪(
-->)规则 - 用户要求“哪些地方调用了这个函数” → 编写调用点规则
仅源查询示例(Java)
当用户询问用户输入、HTTP 端点或可控参数时:
// Find all Spring MVC controller handler methods
*Mapping.__ref__?{opcode: function} as $endpoints;
alert $endpoints;
// Find all user-controllable parameters in Spring controllers
*Mapping.__ref__?{opcode: function}<getFormalParams>?{opcode: param && !have: this} as $params;
alert $params;
// Find GetMapping vs PostMapping endpoints separately
GetMapping.__ref__?{opcode: function} as $getEndpoints;
PostMapping.__ref__?{opcode: function} as $postEndpoints;
alert $getEndpoints;
alert $postEndpoints;
源→汇查询示例(仅在用户要求检测漏洞时)
// RCE: trace user input to exec()
Runtime.getRuntime().exec(* #-> * as $source) as $sink;
alert $sink for {title: "RCE", level: "high"};
// SQL Injection (MyBatis): detect ${} unsafe interpolation in XML mappers / annotations
// <mybatisSink> is a dedicated NativeCall that finds all MyBatis ${} injection points
<mybatisSink> as $sink;
$sink#{
until: `* & $source`,
}-> as $result;
alert $result for {title: "SQLi-MyBatis", level: "high"};
主动提供安全洞见
运行查询并找到结果后,主动提出后续问题和建议。不要只罗列结果就停止。
发现漏洞时:
- 建议修复:“此
exec()调用接收了未经清理的用户输入。建议使用白名单,或使用参数明确分离的 ProcessBuilder。” - 询问相关问题:
- “要我检查是否还有其他端点也调用了
Runtime.exec()吗?” - “要我追踪源和汇之间是否存在输入验证/清理吗?”
- “要我在其他控制器中查找类似模式吗?”
- “要我检查是否还有其他端点也调用了
- 交叉检查:如果发现一种漏洞类型,主动扫描相关类型:
- 发现 RCE → “我还检查了 SSRF,并发现 2 个潜在问题。需要查看详情吗?”
未发现结果时:
- 不要只说“没有结果”——解释原因:
- “没有发现直接的
exec()调用,但我看到了ProcessBuilder的用法。要我改为检查这些用法吗?” - “查询匹配到 0 个汇点。这可能意味着代码使用了框架抽象——要我搜索特定于框架的模式吗?”
- “没有发现直接的
- 建议替代查询
结果模糊时:
- 请求澄清:“我发现了 8 条指向
executeQuery()的数据流路径,但其中 5 条使用了参数化查询(安全)。要我筛选出仅使用字符串拼接的 3 条吗?”
配套参考文件
编写 SyntaxFlow 规则时,使用 Read 工具阅读以下文件,以了解语法并查看实际示例:
| 文件 | 阅读时机 | 路径(相对于此文件) |
|---|---|---|
| NativeCall 参考 | 编写需要 <nativeCallName()> 函数的规则时——包含全部 40 多个 NativeCall 函数的语法和示例 | nativecall-reference.md |
| SyntaxFlow 示例 | 编写新规则时——包含 20 多条适用于 Java/Go/PHP/C 的生产规则,按漏洞类型分类 | syntaxflow-examples.md |
工作流:
- 阅读
syntaxflow-examples.md,查找类似的规则模式 - 需要 NativeCall?阅读
nativecall-reference.md - 通过
ssa_query编写并执行
SyntaxFlow 快速参考
搜索与匹配
documentBuilder // variable name
.parse // method name (dot prefix)
documentBuilder.parse // chain
*config* // glob pattern
/(get[A-Z].*)/ // regex pattern
函数调用与参数
.exec() // match any call
.exec(* as $params) // capture all params
.parse(*<slice(index=1)> as $a1) // capture by index
数据流运算符
| 运算符 | 方向 | 用途 |
|---|---|---|
#> | 向上 1 层 | 直接定义 |
#-> | 向上递归 | 追踪到来源——“它来自哪里?” |
-> | 向下 1 层 | 直接使用 |
--> | 向下递归 | 追踪到最终使用位置——“它会去哪里?” |
.exec(* #-> * as $source) // trace param origin
$userInput --> as $sinks // trace where value goes
$sink #{depth: 5}-> as $source // depth-limited trace
$val #{
include: `*?{opcode: const}`
}-> as $constSources // filter during trace
$sink #{
until: `* & $source`, // stop when reaching source
}-> as $reachable
筛选器 ?{...}
$vals?{opcode: call} // by opcode: call/const/param/phi/function/return
$vals?{have: 'password'} // by string content
$vals?{!opcode: const} // negation
$vals?{opcode: call && have: 'sql'} // combined
$factory?{!(.setFeature)} // method NOT called on value
变量、检查与告警
.exec() as $sink; // assign
check $sink then "found" else "not found"; // assert
alert $sink for { title: "RCE", level: "high" }; // mark finding
$a + $b as $merged; // union
$all - $safe as $vuln; // difference
NativeCall(40 多个内置函数)
最常用的函数——完整列表请参阅 nativecall-reference.md:
<include('rule-name')> // import lib rule
<typeName()> // get short type name
<fullTypeName()> // get full qualified type name
<getReturns> // function return values
<getFormalParams> // function parameters
<getFunc> // enclosing function
<getCall> // find call sites
<getCallee> // get called function
<getObject> // parent object
<getMembers> // object members
<name> // get name
<slice(index=N)> // extract by index
<mybatisSink> // MyBatis SQL injection sinks
<dataflow(include=`...`)> // filter data flow paths
提示
#->=“它来自哪里?”,-->=“它会去哪里?”- 参数使用
*,不要硬编码名称 - SSA 会解析赋值:
a = getRuntime(); a.exec(cmd)=getRuntime().exec(cmd) - 使用
opcode筛选器区分常量/参数/调用 - 结合使用
check+alert,以获得可执行的结果 - 代码变更后,使用
base_program_name(而非re_compile)进行快速增量更新 - 编写新规则前,阅读
syntaxflow-examples.md,查找类似模式 - 不确定 NativeCall 用法时,阅读
nativecall-reference.md,查看用法和示例