sarif-parsing
This skill helps users read, analyze, and process SARIF files from static analysis tools. Use it when you need to aggregate findings from multiple security tools, deduplicate alerts, extract specific vulnerabilities, or integrate scan results into CI/CD pipelines. It covers SARIF structure, fingerprinting for tracking findings across runs, and tool selection guidance for parsing tasks.
git clone --depth 1 https://github.com/trailofbits/skills /tmp/sarif-parsing && cp -r /tmp/sarif-parsing/plugins/static-analysis/skills/sarif-parsing ~/.claude/skills/sarif-parsingSKILL.md
# SARIF Parsing Best Practices
You are a SARIF parsing expert. Your role is to help users effectively read, analyze, and process SARIF files from static analysis tools.
## When to Use
Use this skill when:
- Reading or interpreting static analysis scan results in SARIF format
- Aggregating findings from multiple security tools
- Deduplicating or filtering security alerts
- Extracting specific vulnerabilities from SARIF files
- Integrating SARIF data into CI/CD pipelines
- Converting SARIF output to other formats
## When NOT to Use
Do NOT use this skill for:
- Running static analysis scans (use CodeQL or Semgrep skills instead)
- Writing CodeQL or Semgrep rules (use their respective skills)
- Analyzing source code directly (SARIF is for processing existing scan results)
- Triaging findings without SARIF input (use variant-analysis or audit skills)
## SARIF Structure Overview
SARIF 2.1.0 is the current OASIS standard. Every SARIF file has this hierarchical structure:
```
sarifLog
├── version: "2.1.0"
├── $schema: (optional, enables IDE validation)
└── runs[] (array of analysis runs)
├── tool
│ ├── driver
│ │ ├── name (required)
│ │ ├── version
│ │ └── rules[] (rule definitions)
│ └── extensions[] (plugins)
├── results[] (findings)
│ ├── ruleId
│ ├── ruleIndex (index into tool.driver.rules[])
│ ├── level (OPTIONAL, inherited from the rule when absent)
│ ├── message.text
│ ├── locations[]
│ │ └── physicalLocation
│ │ ├── artifactLocation.uri
│ │ └── region (startLine, startColumn, etc.)
│ ├── fingerprints{}
│ └── partialFingerprints{}
└── artifacts[] (scanned files metadata)
```
### Severity Is Not Always on the Result
`result.level` is optional. CodeQL omits it on every result and records severity on the
rule as `defaultConfiguration.level`, which the result inherits. Read `result.level`
directly and a CodeQL run scores as clean however many errors it found, which is how a
severity gate ends up exiting 0 on a failing repo.
Resolve severity in this order (SARIF 2.1.0 section 3.27.10):
1. `kind` other than `"fail"` (a pass/notApplicable record), so `"none"`
2. `result.level`, when present
3. the matched rule's `defaultConfiguration.level`, joining `ruleIndex` into
`runs[].tool.driver.rules[]`, or matching `ruleId` against `rules[].id` when the tool
omits `ruleIndex`
4. `"warning"`, the SARIF default
Every severity query in this skill starts from that resolution. In jq it is the
`LEVEL_FN` definition in [{baseDir}/resources/jq-queries.md]({baseDir}/resources/jq-queries.md);
in Python it is `resolve_level(result, run)` in
[{baseDir}/resources/sarif_helpers.py]({baseDir}/resources/sarif_helpers.py).
### Why Fingerprinting Matters
Without stable fingerprints, you can't track findings across runs:
- **Baseline comparison**: "Is this a new finding or did we see it before?"
- **Regression detection**: "Did this PR introduce new vulnerabilities?"
- **Suppression**: "Ignore this known false positive in future runs"
Tools report different paths (`/path/to/project/` vs `/github/workspace/`), so path-based matching fails. Fingerprints hash the *content* (code snippet, rule ID, relative location) to create stable identifiers regardless of environment.
## Tool Selection Guide
| Use Case | Tool | Install / run |
|----------|------|--------------|
| Quick CLI queries | jq | `brew install jq` / `apt install jq` |
| Python scripting (simple) | pysarif | `uv run --with pysarif python script.py` |
| Python scripting (advanced) | sarif-tools | `uv run --with sarif-tools python script.py` |
| .NET applications | SARIF SDK | NuGet package |
| JavaScript/Node.js | sarif-js | npm package |
| Go applications | garif | `go get github.com/chavacava/garif` |
| Validation | SARIF Validator | sarifweb.azurewebsites.net |
## Strategy 1: Quick Analysis with jq
For rapid exploration and one-off queries:
```bash
# Pretty print the file
jq '.' results.sarif
# Count total findings
jq '[.runs[].results[]] | length' results.sarif
# List all rule IDs triggered
jq '[.runs[].results[].ruleId] | unique' results.sarif
# Severity resolution, needed by every query below that filters on level.
# See resources/jq-queries.md for the annotated version.
LEVEL_FN='
def rule($run):
. as $r
| ($run.tool.driver.rules // []) as $rules
| (if ($r.ruleIndex | type) == "number" and $r.ruleIndex >= 0
then $rules[$r.ruleIndex] else null end)
// first($rules[] | select(.id == $r.ruleId))
// null;
def level($run):
. as $r
| if ($r.kind // "fail") != "fail" then "none"
else ($r.level // rule($run).defaultConfiguration.level // "warning") end;
'
# Extract errors only
jq "$LEVEL_FN"'.runs[] as $run | $run.results[] | select(level($run) == "error")' results.sarif
# Get findings with file locations
jq '.runs[].results[] | {
rule: .ruleId,
message: .message.text,
file: .locations[0].physicalLocation.artifactLocation.uri,
line: .locations[0].physicalLocation.region.startLine
}' results.sarif
# Filter by severity and get count per rule
jq "$LEVEL_FN"'[.runs[] as $run | $run.results[] | select(level($run) == "error")] | group_by(.ruleId) | map({rule: .[0].ruleId, count: length})' results.sarif
# Extract findings for a specific file
jq --arg file "src/auth.py" '.runs[].results[] | select(.locations[].physicalLocation.artifactLocation.uri | contains($file))' results.sarif
```
## Strategy 2: Python with pysarif
For programmatic access with full object model:
```python
from pysarif import load_from_file, save_to_file
# Load SARIF file
sarif = load_from_file("results.sarif")
# Iterate through runs and results
for run in sarif.runs:
tool_name = run.tool.driver.name
print(f"Tool: {tool_name}")
for result in run.results:
# pysarif fills a missing result.level with "warning", so .level here is NOT the
# rule-inherited severity: aAudits GitHub Actions workflows for security vulnerabilities in AI agent integrations including Claude Code Action, Gemini CLI, OpenAI Codex, and GitHub AI Inference. Detects attack vectors where attacker-controlled input reaches AI agents running in CI/CD pipelines, including env var intermediary patterns, direct expression injection, dangerous sandbox configurations, and wildcard user allowlists. Use when reviewing workflow files that invoke AI coding agents, auditing CI/CD pipeline security for prompt injection risks, or evaluating agentic action configurations.
Clarify requirements before implementing. Use when serious doubts arise.
Understand a codebase before looking for bugs in it - what each function assumes, what it guarantees, and what it depends on elsewhere. Use when starting an audit, threat model, or architecture review on unfamiliar code, and before any vulnerability-hunting pass.
Scans Algorand smart contracts for 11 common vulnerabilities including rekeying attacks, unchecked transaction fees, missing field validations, and access control issues. Use when auditing Algorand projects (TEAL/PyTeal).
Prepares codebases for security review using Trail of Bits' checklist. Helps set review goals, runs static analysis tools, increases test coverage, removes dead code, ensures accessibility, and generates documentation (flowcharts, user stories, inline comments). Use when preparing your own codebase to be audited by someone else, getting a repository review-ready before an external security review, deciding what to fix before auditors start, or asking what assessors need from a project. For understanding unfamiliar code you are about to audit, use audit-context-building instead.
Scans Cairo/StarkNet smart contracts for 6 critical vulnerabilities including felt252 arithmetic overflow, L1-L2 messaging issues, address conversion problems, and signature replay. Use when auditing StarkNet projects.
Systematic code maturity assessment using Trail of Bits' 9-category framework. Analyzes codebase for arithmetic safety, auditing practices, access controls, complexity, decentralization, documentation, MEV risks, low-level code, and testing, then produces a scorecard with evidence-based ratings and a priority-ordered roadmap. Use when assessing or scoring the maturity of a smart contract or blockchain codebase, producing a maturity scorecard or evaluation, or judging how mature, well-tested, or well-documented such a project is against a rubric.
Scans Cosmos SDK blockchain modules and CosmWasm contracts for consensus-critical vulnerabilities — chain halts, fund loss, state divergence. 25 core + 16 IBC + 10 EVM + 3 CosmWasm patterns. Use when auditing custom x/ modules, reviewing IBC integrations, or assessing pre-launch chain security. Updated for SDK v0.53.x.