romansok/vuln-analyzer
GitHub: romansok/vuln-analyzer
Stars: 0 | Forks: 0
# vuln-analyzer
An agentic vulnerability analyzer for Claude Code (and Cursor). Runs a
Grype scan over a target, ranks findings by grype's unified risk, shows
a **top-5 table** in chat, and dispatches a four-agent analysis pipeline
for the **top 2** — reachability, contextualization, remediation, and a
synthesizing lead agent — to produce one developer-readable report per
vulnerability. Rows 3–5 are listed for awareness; ask the standalone
`vulnerability-analyzer` agent (e.g. `analyze GHSA-…`) for deep analysis
on any specific id.
## Requirements
- **OS:** macOS, Linux, or Windows + WSL. Native Windows cmd / PowerShell
is **not** supported — the skill uses POSIX shell tools.
- **Tools:** `bash` (3.2+), `date`, `python3` (3.8+) — all pre-installed on macOS / Linux / WSL.
`jq` (1.6+) is strongly recommended; if it's missing, a bundled
Python stdlib-only fallback (`jq-fallback.py`) handles the same
operations with byte-identical output.
- **Client:** Claude Code or Cursor with the [grype MCP server](https://github.com/romansok/grype-mcp/)
configured.
## How to use (once installed)
1. Open Claude Code (or Cursor) in any project. The skill and the four
agents work from any working directory once they're installed
user-level (see [INSTALL.md](INSTALL.md)).
2. Ask in plain English. Any of these will trigger the skill:
- *"Scan /Users/me/repo for vulnerabilities."*
- *"Audit dependencies in this project."* (uses your cwd)
- *"Run grype on /path/to/project."*
- *"Check the security of this codebase."*
The skill scans **local directories only.** If you pass an image
ref, SBOM, PURL, or CPE it's politely rejected with a pointer to
running grype directly. For a specific advisory id without
scanning, ask the `vulnerability-analyzer` agent directly instead
(see [Standalone analyzer](#standalone-analyzer) below).
3. To analyze a single vulnerability standalone (no scan):
- *"Analyze CVE-2023-32314."*
- *"Tell me about GHSA-whpj-8f3w-67p5."*
- *"Explain https://github.com/advisories/GHSA-whpj-8f3w-67p5."*
## What you'll get
- **Inline in chat:**
- Scan summary line — target, total matches, distinct vulns.
- Severity counts — Critical / High / Medium / Low / Negligible (all five, including zeros).
- **Top-5 markdown table** — sorted by risk, columns: `VulnID | Risk | Severity | CVSS | PURL(s) | Fix | Description`.
- **One synthesis block per top-2 finding**, structured for fast triage:
- **Bug class** — the CWE(s).
- **Attack surface** — *who* can exploit this, *from where*, *with what access* (e.g. `network (unauthenticated remote)`, `api (admin token required)`, `local (must execute on the host)`). Copy-paste-ready into a Slack message.
- **What an attacker gets** — concrete consequence (RCE on the worker, exfil the session cookie, DoS the request handler) — not the mechanism.
- **Reachable in this codebase?** — verdict + file:line evidence when found.
- **What to do** — the upgrade path (bump / config-toggle / no-upstream-fix).
- **Workaround (always emitted)** — a concrete code or config snippet you can drop in **today** when bumping is blocked (peer-dep conflict, vendored fork, EOL framework, waiting on a PR review). Code block, language-fenced, plus the cost in one sentence.
- **Why it matters (10s explanation)** — one-line example a generalist developer follows.
- **Confidence** — High / Medium / Low + what would raise it.
Rows 3–5 in the table are not deeply analyzed by default — ask the standalone `vulnerability-analyzer` agent (`analyze `) for any of them on demand.
- **On disk (only if total findings > 5):**
- `vulnerabilites_report_.md` in your invocation cwd. Contains **only** the full per-match markdown table — every artifact location for every finding. The absolute path is printed in chat.
## Architecture
SKILL.md (orchestrator)
├─ Scans with mcp__grype__scan (output_format=json)
├─ Caches JSON; reads it only via jq snippets
├─ Ranks, renders, writes the report file
└─ Dispatches 2 × Task(vulnerability-analyzer) IN PARALLEL — one for each of the top-2 vulns
│
▼
vulnerability-analyzer (lead) ×2 concurrent instances
1. Validates the input (CVE / GHSA / advisory URL).
2. Resolves vuln context (cache file, fetched URL, or self-gathered).
3. Extracts the vulnerable symbols (functions, classes, sinks,
config toggles) from the advisory — this is what reachability
needs to actually search for.
4. Fans out 3 Task calls IN PARALLEL:
• reachability-analyzer — receives the extracted symbols and decides how/where to grep.
• context-analyzer — explains the bug class in plain English (uses local CWE playbook).
• remediation-analyzer — primary fix + ranked workarounds, informed by the symbols.
5. Synthesizes one developer-readable block and returns it.
The SKILL collects both returned blocks, then emits them inline in the
risk-sorted order of the top-5 table — first the #1 row's synthesis,
then the #2 row's. Two-tier parallelism (2 leads × 3 sub-agents each
= 6 concurrent sub-agents) brings wall time down to roughly the
slowest single chain.
## Repository layout
Tool-agnostic source — the `install.sh` script copies these into
`~/.claude/` or `~/.cursor/` (or a project-local equivalent) depending
on the flag you pass.
.
├── install.sh Installs into Claude Code or Cursor.
├── README.md
├── INSTALL.md
├── LICENSE
├── agents/ The four agents (lead + three sub-agents).
│ ├── vulnerability-analyzer.md
│ ├── reachability-analyzer.md
│ ├── context-analyzer.md
│ └── remediation-analyzer.md
├── skills/
│ └── vuln-analyzer/
│ ├── SKILL.md Thin orchestrator. Highest authority.
│ └── references/ Read by the skill / agents on demand.
│ ├── jq-snippets.md Canonical jq commands.
│ ├── jq-fallback.py Python stdlib-only fallback for jq.
│ ├── output-templates.md Exact markdown for tables and synthesis blocks.
│ ├── grype-schema-cheatsheet.md Field map for the grype JSON.
│ └── cwe/ One file per seeded CWE + an index.
│ ├── index.md
│ └── CWE-20.md … CWE-1321.md
└── settings/
└── claude-permissions.json Optional. Claude-only. Pre-approves common Bash + WebFetch hosts.
After install, the agents and skill live under your AI assistant's
config directory:
- Claude Code: `~/.claude/agents/*.md` and `~/.claude/skills/vuln-analyzer/`
- Cursor: `~/.cursor/agents/*.md` and `~/.cursor/skills/vuln-analyzer/`
Runtime artifacts (`.cache/grype_scan_.json`, `.cache/vuln_.json`)
are written under the installed skill dir at scan time; the
`vulnerabilites_report_.md` is written to the user's cwd. None of
these belong in this repo.
## Sort order
Findings are ordered by, in this priority:
1. `vulnerability.risk` — grype's unified score (fuses CVSS, EPSS, KEV, fix availability). Descending.
2. Max `cvss[].metrics.baseScore`. Descending.
3. Severity bucket: Critical → High → Medium → Low → Negligible.
4. Vuln id lexicographic (full determinism on ties).
The top 5 are distinct vuln ids — same id on multiple PURLs collapses to a single row in the inline table. The report file keeps every per-artifact row.
## Standalone analyzer
The lead agent (`vulnerability-analyzer`) works **outside the skill
flow** — invoke it directly any time you want a developer-grade
analysis of a single vulnerability, without running a scan first.
It accepts natural language:
analyze CVE-2024-1234
what does GHSA-whpj-8f3w-67p5 mean for us?
explain RUSTSEC-2024-0001
look at https://github.com/advisories/GHSA-xxxx-xxxx-xxxx
analyze https://security-tracker.debian.org/tracker/CVE-2024-1234
Validation order: **URL first, id second.** If the input contains a URL,
the host must be on the allowlist; the URL becomes the sole source of
truth. Otherwise the input must look like an advisory id — any token
of the shape `-` where the prefix is uppercase
letters.
Supported id prefixes (the agent recognizes the prefix and picks the
right database):
| Prefix | Source |
| --- | --- |
| `CVE-` | MITRE / NVD |
| `GHSA-` | GitHub Security Advisories |
| `OSV-` | OSV.dev |
| `SNYK-` | Snyk |
| `PYSEC-` | Python Packaging Advisory |
| `RUSTSEC-` | Rust Security Advisory |
| `GO-` | Go vuln DB |
| `DSA-`, `DLA-` | Debian Security / Long-Term |
| `RHSA-` | Red Hat Errata |
| `USN-` | Ubuntu Security Notice |
| `ALAS-` | Amazon Linux |
| `ELSA-` | Oracle Linux |
| `ALSA-` | AlmaLinux |
| (other) | falls back to OSV → WebSearch |
Behavior by input kind:
- **Bare id** → the agent picks the canonical fetch URL for that
prefix, gathers context, extracts vulnerable symbols, and dispatches
the three sub-agents. Reachability returns `source-not-available`
because there's no project root to search — context + remediation
still produce useful output.
- **Advisory URL** → that URL is treated as the **only** source of
truth. No other lookups.
- **Invalid / unrecognized** → a single sentence of rejection. No
sub-agents are dispatched.
When invoked by the skill (during a scan), the same agent receives a
structured prompt with a context-file path and a project root — it
follows the same flow, but reachability has real source to grep.
## Caveats and notes
- **Cross-platform.** The skill uses `jq`, `awk`, `bash`, and `date` —
POSIX tools available out of the box on macOS / Linux / WSL. Native
Windows isn't supported; use WSL or git-bash. See [INSTALL.md](INSTALL.md#1-prerequisites)
for installer commands.
- **JSON stays out of context.** The full grype JSON is written to a
`.cache/` dir under the installed skill and only read via `jq` from
Bash. The model never loads it.
- **Directory scans only.** The skill targets local directories
exclusively — image refs, SBOM files, PURLs, and CPEs are rejected
at Phase 1 with a pointer to running grype directly. The standalone
`vulnerability-analyzer` agent (invoked outside the skill) is the
way to analyze a specific advisory id without a scan.
- **Reachability returns `source-not-available`** only in standalone
mode (the agent was invoked outside the skill with no project root).
Skill scans always have a real source tree.
- **Filename spelling.** `vulnerabilites_report_.md` preserves the
spelling from the original spec (the maintainer is aware
"vulnerabilities" is the standard spelling).
- **Gitignore.** Add `.cache/` and `vulnerabilites_*.md` to
`.gitignore` if this directory becomes a git repo.
## Adding a new CWE to the playbook
In this repo:
1. Copy the template from skills/vuln-analyzer/references/cwe/index.md (bottom).
2. Save as skills/vuln-analyzer/references/cwe/CWE-.md.
3. Add a row to skills/vuln-analyzer/references/cwe/index.md.
4. Re-run ./install.sh to publish the change to your installed location.
标签:自动化攻击