A model's training data is months old. Advisories are published every day. opencraysec gives your
AI assistant (or you, on the command line) a fast way to check a project's dependencies against
today's public advisories, rank what matters, say whether your own code uses the vulnerable
package, and prove a fix worked. Every scan, fix and verification is logged, so you can see what the
assistant changed, and why, in a dashboard.
One static binary. An MCP server and a CLI. No account, no API key, and your source code never leaves your machine.
What you get
- Many languages: Rust, JavaScript/TypeScript, PHP, Go and Python lockfiles, and the GitHub Actions your workflows use.
- Current, public data only: OSV (which aggregates GitHub Advisories, RustSec, the Go vulnerability database and more), the CISA Known Exploited Vulnerabilities list, FIRST EPSS scores, the MITRE CWE catalog and NVD scores. CVE ids, CWE weakness classes and CVSS come with the advisories. See docs/DATA-SOURCES.md.
- Malicious packages: reports from the OpenSSF Malicious Packages project (through OSV) are flagged and listed first, with "remove it" instead of an upgrade command.
- Install-time code: lists the npm packages whose lockfile says an install script runs code on install, and names the lockfiles that cannot say (it is not a vulnerability, and never fails a gate).
- Ranked, not just listed: malicious first, then exploited in the wild, then likely to be exploited, then CVSS.
- Is it actually used? Usage evidence per finding from your own source: for Rust and Go down to the affected function. Findings your code does not import sink in the ranking (never hidden).
- Fix, verify, record:
plan_fixgives the exact upgrade commands,verify_fixre-scans and tells you which advisories are gone,record_fixlogs what was changed and why, like a commit message. An id isresolvedonly when an earlier scan of the same path reported it; an id no earlier scan reported isunknown, and that proves nothing. - The runtime underneath too:
scan-runtimechecks PHP, nginx, Node.js, databases and similar products that no lockfile lists, and says whether their release line is end of life or behind its newest patch, the day a fix ships. With--nvdit also lists the CVEs NVD records for that exact version, which is how a flaw in PHP itself shows up. - Your CI too: the actions a workflow uses are checked against the same advisory data (a full release
tag is matched; a commit SHA, a floating tag or a branch is listed as not checked, never dropped), and
scan-codeflags dangerous workflow patterns: text an outsider controls pasted into arun:script, apull_request_targetworkflow that checks out the pull request, an unpinned action and a token with every permission, each with the guidance it rests on (docs/LANGUAGES.md). - Your own code too:
scan-codeflags suspected hard-coded secrets, injection patterns, disabled TLS verification and unsafe deserialization, each with a CWE, and can run gitleaks or semgrep. For code that calls an AI model it also looks for provider keys (Anthropic, Hugging Face, Google), a model's answer passed toeval, a shell, SQL or HTML, and a prompt built from a request's input, with the OWASP LLM Top 10 entry behind each rule. - The files that steer your assistant:
scan-agent-configreads rule files (CLAUDE.md,AGENTS.md,.cursorrules, ...), MCP server settings, hooks, auto-run tasks and skills (a folder with aSKILL.md: its text, scripts and dependencies) for invisible characters, injected instructions, commands that download and run code, unpinned packages, compiled files and secrets, and checks the packages an MCP server or a skill starts or lists against the same advisory and malicious-package data. Every rule names its CWE and the OWASP entry behind it (docs/AGENT-CONFIG.md). - A report people can read: a read-only dashboard with charts, the vulnerability list and the history of fixes with references, or the same report as one HTML file.
- Honest: every result says what was scanned, what was not, and how old the data is. A clean result means no known advisory matched, not secure.
The images come from a scratch project (
/tmp/shop-api) written for the demonstration, with real advisory data: the findings and numbers are what opencraysec reported. One package in it is a real entry from the public malicious-package data. The fix history was recorded by a script standing in for an assistant: it edited the lockfile and then ranrecord-fixandverify-fix, which is why the client is shown ascli. No customer data or personal paths are shown.
curl -fsSL https://raw.githubusercontent.com/amgio38/opencraysec/main/scripts/install.sh | sh
opencraysec update --for . # download advisories for the ecosystems in this project
opencraysec scan . # and check it
claude mcp add opencraysec -- opencraysec mcp| Platform | How |
|---|---|
| Linux x86-64, aarch64 | The command above downloads a prebuilt static binary and checks its SHA-256. No Rust needed. |
| macOS, Apple Silicon and Intel | The same command downloads a prebuilt native binary and checks its SHA-256. No Rust or Xcode needed. |
| Other Linux CPUs | The same command builds from source (Rust 1.95+ and a C compiler). |
| Windows | Run it inside WSL2 (below). The installer refuses native Windows shells. |
A prebuilt binary for every supported platform is attached to each release, with a .sha256 file beside it; docs/INSTALL.md shows how to verify a download by hand.
The first line installs opencraysec into ~/.local/bin. Other clients (Cursor, opencode, Codex),
system-wide installs and uninstalling are in docs/INSTALL.md and
docs/CLIENTS.md.
To teach the assistant the workflow, install the bundled Agent Skill: copy it once for every project, or into this project only.
cp -r skills/opencraysec ~/.claude/skills/ # every project
cp -r skills/opencraysec .claude/skills/ # this project onlyFrom PowerShell, once (this installs Ubuntu and asks for a reboot):
wsl --install -d UbuntuThen open the Ubuntu app and install exactly as on Linux:
curl -fsSL https://raw.githubusercontent.com/amgio38/opencraysec/main/scripts/install.sh | shRun your coding agent inside WSL as well, and keep your projects on the Linux side
(~/projects, not /mnt/c/...): the lockfiles are then read at native speed, and the paths the
tools report match what the agent sees.
opencraysec scan . # human-readable report, most urgent first
opencraysec scan . --format sarif -o out.sarif # also: json, cyclonedx (SBOM)
opencraysec scan bom.json # a CycloneDX or SPDX SBOM: an image's inventory, another machine's list
opencraysec scan . --fail-on high # exit 1 in CI if anything is high or worse, 3 if nothing was checked
opencraysec scan . --enrich-nvd # score findings the advisories left unscored
opencraysec explain GHSA-xxxx-xxxx-xxxx # what it is, how bad, references
opencraysec plan-fix . # the upgrade commands; nothing is modified
opencraysec verify-fix . --id GHSA-xxxx-xxxx-xxxx # re-scan; "resolved" needs an earlier scan of this path
opencraysec record-fix . --id GHSA-xxxx-xxxx-xxxx --summary "Upgrade lodash" --reason "Prototype pollution"
opencraysec scan-code . # suspected weaknesses in your own source
opencraysec scan-agent-config . # rule files, MCP servers, hooks and skills of your AI assistant
opencraysec scan-runtime # PHP, nginx, Node.js ... installed here: end of life? behind?
opencraysec scan-runtime php@8.2.30 # or name the versions, for a container or another machine
opencraysec scan-runtime --nvd # also the CVEs NVD lists for those versions (network)
opencraysec dashboard # the report on http://localhost:1787
opencraysec report -o report.html # the same report as one file
opencraysec status # what data is stored, and how oldscan works without downloading anything: for an ecosystem with no local data it asks the OSV API about
the exact package names and versions it found (never your code) and says so in the report. --offline
forbids that. Run update once for fully offline scans.
scan --fail-on exits 1 when it found something at or above the threshold, and 3 when a pass would prove
nothing: no lockfile, an unreadable lockfile, an ecosystem with no advisory data, or only requirement lines
without an exact == pin. Requirement lines listed next to dependencies that were checked do not fail the
gate; the report then says it is incomplete. verify-fix exits 1 when a finding remains, an id is
unknown, or the result could not be trusted. The full table is in
docs/CONFIGURATION.md.
{
"mcpServers": {
"opencraysec": { "command": "opencraysec", "args": ["mcp", "--workspace", "/path/to/project"] }
}
}| Tool | Purpose |
|---|---|
scan_dependencies |
Check lockfiles against current advisories, ranked, with usage evidence. |
scan_code |
Suspected weaknesses in the project's own source. |
scan_agent_config |
Rule files, MCP server settings, hooks, auto-run tasks and skills that steer an AI assistant. |
scan_runtime |
Installed interpreters, servers and databases against release and end-of-life data. |
explain_advisory |
One advisory: what it is, CWE, exploitation signals, references. |
plan_fix |
The minimal upgrades and the commands to run. Modifies nothing. |
verify_fix |
Re-scan and prove advisories are gone (and whether that proof can be trusted). |
record_fix |
Optional, like a commit message: what the assistant changed and why. |
update_db |
Download or refresh the advisory data. |
db_status |
What data is stored, and how old it is. |
Paths are confined to --workspace. The server never edits your project: it tells the assistant what to
run, and record_fix writes only to the activity log. Full arguments and results are in
docs/TOOLS.md.
opencraysec dashboard serves a read-only report from the activity log: counts, severity over time, the
riskiest packages, usage evidence, activity, the vulnerable dependencies, the packages that run code
when installed, the runtime products (scan-runtime) with the CVEs NVD lists for them, the assistant
configuration findings, suspected code issues, and the history of what was changed and why.
It listens on every network interface by default (0.0.0.0:1787) and the report lists your
vulnerabilities. Use --host 127.0.0.1 to keep it on this machine, or --token SECRET to require one.
Details, including what the log holds, are in docs/DASHBOARD.md.
- Dependency matching uses lockfile versions. Usage evidence is source text, not a call graph: it
can miss dynamic use and cannot see use by other dependencies, so
not_foundmeans "your code does not import it", not "safe". For Go, rungovulncheckfor a call-graph proof. scan-agent-configis pattern matching too: it cannot see what an MCP server or a skill does once it runs, only what it is made of and the package it is started from. See docs/AGENT-CONFIG.md for each rule's false positives and misses.scan-codeis pattern matching with a small rule pack. Every hit is suspected; confirm it before reporting.- A
requirements.txtentry without an exact==pin cannot be matched. CVSS v4 vectors are not computed locally;--enrich-nvdfetches NVD's score. - The activity log is not rotated.
Scanning is local. The only network traffic is downloading public datasets (OSV, CISA, FIRST, MITRE,
endoflife.date, php.net), querying api.osv.dev with package names and versions when an ecosystem has no
local data and you did not pass --offline, and NVD lookups when you pass --enrich-nvd (CVE ids) or
scan-runtime --nvd (a product's CPE name and version). The activity log holds package names, versions,
advisory and CVE ids and file paths, never source code or secrets, and stays on your machine. See docs/CONFIGURATION.md.
| docs/INSTALL.md | Installing, building, uninstalling, verifying a download |
| docs/CLIENTS.md | Claude Code, Cursor, opencode, Codex and any other MCP client |
| docs/TOOLS.md | Every MCP tool, its arguments and results |
| docs/LANGUAGES.md | Supported lockfiles, usage evidence, fix commands, code rules |
| docs/AGENT-CONFIG.md | scan-agent-config: what it reads, every rule with its CWE and OWASP entry, and its limits |
| docs/DASHBOARD.md | The report, the log, and who can see them |
| docs/DATA-SOURCES.md | Where every fact comes from, and how findings are ranked |
| docs/CONFIGURATION.md | Data directory, environment variables, limits, exit codes |
| docs/TROUBLESHOOTING.md | Common problems |
| docs/ARCHITECTURE.md | How the crates fit together and why |
| docs/RELEASING.md | How a release is cut |
| Crate | Role |
|---|---|
opencraysec-core |
Package model, per-ecosystem version ordering, CVSS v3, OSV matching. |
opencraysec-lockfile |
Lockfile and SBOM discovery and parsers. |
opencraysec-runtime |
Runtime products (PHP, nginx, ...): version detection, release and end-of-life verdicts, NVD answers. No network. |
opencraysec-db |
Local store, dataset updates, the OSV and NVD clients, the release-data feeds. |
opencraysec-engine |
Scan, usage evidence, code rules, explain, plan and verify fix, SARIF and CycloneDX. |
opencraysec-log |
The activity log (JSONL), dependency snapshots and report summaries. |
opencraysec-web |
The read-only dashboard server and the HTML export. |
opencraysec-mcp |
The MCP stdio server. |
opencraysec-cli |
The opencraysec binary. |
Build and test with make ci (format, clippy, tests, layering, licence, installer and docs checks) and
make preflight before every push (the same list CI runs, plus the 90% coverage gate). See
CONTRIBUTING.md for the conventions.
MIT. See LICENSE and SECURITY.md.
Dependencies are under their own licenses: see THIRD-PARTY-LICENSES.md for the
crate-by-crate inventory and NOTICE for the required attributions. The licence texts those
require are in licenses/. deny.toml is the policy and make deny is the gate; CI runs it
on every push. The vulnerability data opencraysec downloads belongs to its publishers; see
docs/DATA-SOURCES.md.
An installed copy carries all of it: install.sh and make install put this set under
$PREFIX/share/doc/opencraysec, the release archive carries it so there is something to install, and
both uninstall paths remove it.
The crates in this workspace are marked publish = false in their Cargo.toml. That is deliberate:
they are released as the opencraysec binary, not as a library for others to depend on. It also means
cargo install opencraysec from crates.io does not work and is not intended; use the installer above, or
build from a checkout with cargo build --release -p opencraysec-cli.


