A developer environment security and health scanner. Detects runtimes, inspects installed packages, and surfaces known vulnerabilities and outdated dependencies — across your global environment or a specific project.
Built with Go. Designed to be scriptable, CI-friendly, and extensible.
# Latest release
go install github.com/DevShedLabs/devscan@latest
# Specific version
go install github.com/DevShedLabs/devscan@v0.1.4Make sure ~/go/bin is on your $PATH. Add this to your shell profile (~/.zshrc, ~/.bashrc, etc.)
if it isn't already:
export PATH="$HOME/go/bin:$PATH"Then reload your shell (source ~/.zshrc) or open a new terminal.
Once installed, keep devscan up to date with:
devscan updateOr build from source:
git clone https://github.com/DevShedLabs/devscan
cd devscan
go build -o devscan .| Command | Description |
|---|---|
devscan doctor |
Full scan: runtimes, packages, vulnerabilities, outdated deps |
devscan audit |
Vulnerabilities only |
devscan outdated |
Version drift only |
devscan list |
Inventory of detected runtimes and packages |
devscan locate |
Filesystem paths for every vulnerable package |
devscan scan |
Raw JSON scan output for piping |
devscan fix |
Suggested fix commands |
devscan report |
Export a full report as Markdown, HTML, or JSON |
devscan keyscan |
Scan files for exposed secrets, API keys, and tokens |
devscan osv |
Search OSV for advisories by package name, ID, or keyword |
devscan compile |
Compile blocklist resources into a single index |
devscan update-db |
Fetch latest blocklist databases and recompile |
devscan intercept |
Manage package manager shims for real-time install protection |
devscan install-skill |
Install the Claude Code AI skill into ~/.claude/skills/ |
devscan update |
Update devscan to the latest release |
All commands scan the current directory by default. Use --global to scan the entire machine instead.
# Get the version you have installed
devscan --version
# Full health report for the current project
devscan doctor
# Audit the current project for vulnerabilities
devscan audit
# Scan the whole machine (global packages)
devscan audit --global
# Filter to high severity and above
devscan audit --severity high
# Show exactly where vulnerable packages are installed
devscan locate
# Scan a specific path
devscan doctor --path ./my-app
# Scan a project and all sub-projects up to 2 levels deep
devscan doctor --path ./my-app --depth 2
# Machine-readable output
devscan doctor --format json
# CI: exit non-zero if critical vulns found
devscan audit --severity criticalGenerate a shareable report in Markdown, HTML, or JSON:
# Format is inferred from the output file extension
devscan report --output report.html
devscan report --output report.md
devscan report --output scan.json
# Or specify the format explicitly (stdout)
devscan report --html
devscan report --md
devscan report --json
# Scoped to a path
devscan report --output report.html --path ./my-app
# Traverse sub-projects
devscan report --output report.html --path ./my-app --depth 2
# Clean public report (strips internal paths and package inventory)
devscan report --output security-report.md --publicReports include:
- System info: OS, version, chip, architecture
- Summary cards with severity counts and scan duration
- Runtime versions with outdated status
- Vulnerabilities grouped by severity, with OSV advisory links, fixed-in versions, and fix commands
- Filesystem paths for every vulnerable package installation
- Full package inventory
Augment OSV vulnerability data with your own curated supply-chain blocklists. Any package matched against a blocklist is reported as critical severity alongside normal OSV findings.
The fastest way to get started is to fetch the latest databases directly from Aikido's open-source threat intelligence feed:
devscan update-dbThis downloads the npm and PyPI malware databases from malware-list.aikido.dev, saves them to ~/.devscan/resources/, and compiles the index automatically. devscan update also runs this step so your databases stay current whenever you update the binary.
You can also drop your own blocklist files into ~/.devscan/resources/ and compile manually:
devscan compileThis writes ~/.devscan/devscan.json. All subsequent scans load the compiled index automatically — no flags needed, no rebuild required.
After adding or updating source files, re-run devscan compile to regenerate the index.
CSV — header row required, Ecosystem and Name columns required, Version optional (omit to match any version):
Ecosystem,Namespace,Name,Version,Artifact,Published,Detected
npm,,chai-utils-test,4.5.3,,,2026-06-04T00:00:00Z
pypi,,tlask,3.1.4,,,2026-06-07T15:00:00Z
JSON (generic) — ecosystem must be specified:
[
{ "ecosystem": "npm", "name": "evil-pkg", "version": "1.0.0", "reason": "MALWARE" }
]JSON (Aikido-style) — auto-detected by the package_name field, treated as npm:
[
{ "package_name": "evil-pkg", "version": "1.0.0", "reason": "MALWARE" }
]Packages flagged by multiple sources are merged into a single finding. The vulnerability description lists every source file that matched, e.g.:
[CRIT] chai-utils-test@4.5.3
Malware detected
This package appears in malwareDatabase_js.json, miasma-attack-packages.csv.
Reason: MALWARE. Remove or replace it immediately.
~/.devscan/
resources/ ← drop source files here (*.csv, *.json)
devscan.json ← compiled index (auto-used by all scans)
advisories.yaml ← global user advisories (optional)
<project>/
.devscan/
advisories.yaml ← project-scoped advisories (optional, commit to repo)
When a security company publishes a disclosure about a compromised package, OSV.dev can take days or weeks to reflect it. User advisories let you flag a package immediately — no waiting, no recompile.
Create .devscan/advisories.yaml in your project root (committed to your repo) or ~/.devscan/advisories.yaml for a global advisory that applies to all projects:
advisories:
- ecosystem: crates.io
package: onering
version: "*" # all versions
severity: critical
reason: "Package compromised — backdoor injected"
reference: "https://blog.sec.com/2026/06/onering"
- ecosystem: npm
package: left-pad
version: "1.2.3" # specific version only
severity: high
reason: "Malicious version published"
reference: "https://..."version: "*" matches every installed version. A specific version (e.g. "1.2.3") matches only that exact release.
User advisories are merged on top of the compiled blocklist every time devscan runs. No recompile step needed — drop the file and rescan.
To check your system against your advisories without sending every package to OSV, use --advisories-only:
# Fast, private — no network calls to OSV
devscan audit --advisories-only
# Global scan against your custom advisories only
devscan audit --advisories-only --globalThis is useful when you've just added an advisory and want to check whether the package is present on your machine, without the latency or data exposure of a full OSV scan.
Matched packages are reported as critical severity findings alongside OSV and blocklist results, and the reference URL is included in the finding description.
If you have intercept shims enabled, user advisories also block installs before the package is fetched:
╔══════════════════════════════════════════════════════════════════════╗
║ DEVSCAN BLOCKED ║
╚══════════════════════════════════════════════════════════════════════╝
[CRITICAL] onering
Package compromised — backdoor injected — https://blog.sec.com/2026/06/onering
cargo add was blocked. Remove this package from your command and try again.
| File location | Scope |
|---|---|
.devscan/advisories.yaml |
Project only — commit to share with your team |
~/.devscan/advisories.yaml |
All projects on this machine |
Both files are loaded simultaneously when present.
Scan source files for exposed secrets, API keys, and tokens:
# Scan current directory
devscan keyscan
# Scan a specific path
devscan keyscan --path ./my-app
# Limit depth (useful for large monorepos)
devscan keyscan --path /Users/me/projects --depth 3
# Filter to critical only
devscan keyscan --severity critical
# Export as HTML or Markdown
devscan keyscan --path ./ --format html --output keyscan.html
devscan keyscan --path ./ --format md --output keyscan.md
# Redirect output (also enables live progress counter)
devscan keyscan --path /Users/me/projects --depth 3 > keyscan.htmlDetected secret types:
| Category | Examples |
|---|---|
| AI providers | OpenAI, Anthropic, Google AI, Groq, OpenRouter, Cohere, Replicate |
| Cloud | AWS access/secret keys, GCP service accounts, Firebase, Azure |
| Source control | GitHub tokens (ghp_, ghs_, gho_, github_pat_) |
| Payments | Stripe live keys (sk_live_, pk_live_), PayPal, Braintree |
| Messaging | Slack tokens & webhooks, Twilio, SendGrid, Mailgun |
| Registries | npm tokens |
| Infrastructure | Heroku, Vercel, Netlify, Render, Cloudflare, DigitalOcean |
| Monitoring | Datadog, Sentry, New Relic |
| Private keys | RSA, EC, DSA, OpenSSH private key headers |
| Database URLs | Postgres, MySQL, MongoDB, Redis URLs with embedded credentials |
| Named vars | Any <SERVICE>_KEY, <SERVICE>_TOKEN, <SERVICE>_SECRET where the service name is a known provider |
Skips automatically: node_modules/, vendor/, .git/, dist/, binary files, documentation (.md, .rst, .txt), and example/template files (.example, .sample, .dist).
All matched values are redacted in output — only enough context is shown to identify the type of secret, never the full value.
Add a secrets section to any devscan report:
devscan report --html --include-keys --output report.html
devscan report --md --include-keys
devscan report --json --include-keys --output report.json--format string Output format: table|json|compact (default "table")
--severity string Filter by severity: critical|high|medium|low
--ecosystem string Filter by ecosystem: npm|pypi|packagist|crates.io|go
--global Scan global packages (machine-wide)
--project Scan current project directory (default)
--path string Explicit project path to scan
--depth int Traverse subdirectories up to this depth (0 = path only)
--no-color Disable color output
--no-cache Bypass cache and force a fresh advisory lookup
--advisories-only Match only user advisories and blocklists — skip OSV network lookup
--public Removes data not needed for public view, eg. repo
-o, --output string Write report to file (report command only)
When a fix is available, devscan generates the exact command to run:
| Ecosystem | Example |
|---|---|
| npm | npm install pkg@^1.2.3 |
| pypi | pip install --upgrade pkg>=1.2.3 |
| packagist | composer require vendor/pkg:^1.2.3 |
| crates.io | cargo update -p pkg --precise 1.2.3 |
| go | go get module@v1.2.3 |
| gem | gem update pkg |
| Code | Meaning |
|---|---|
0 |
Clean |
1 |
General error |
2 |
Vulnerabilities found |
3 |
Critical vulnerabilities found |
4 |
Outdated packages found |
Useful for CI pipelines:
- name: Security scan
run: devscan audit --severity highIntercept wraps npm, pip, cargo, and bun with shims that check every explicit package install against your compiled blocklist before the package is fetched — before any postInstall hook can execute.
Most supply-chain attacks run malicious code during installation via post-install hooks, and use tools like Bun and Rust to do further damage on the machine. Intercept stops them at the gate.
When enabled, devscan writes symlinks into ~/.devscan/shims/:
~/.devscan/shims/npm → devscan binary
~/.devscan/shims/pnpm → devscan binary
~/.devscan/shims/bun → devscan binary
~/.devscan/shims/pip → devscan binary
~/.devscan/shims/pip3 → devscan binary
~/.devscan/shims/cargo → devscan binary
~/.devscan/shims/go → devscan binary
~/.devscan/shims/composer → devscan binary
The shims directory sits at the front of your PATH. When you run npm install evil-pkg, the shim runs first, checks the package against your compiled blocklist, and either blocks with a warning or transparently execs the real binary. Non-install commands (npm run, cargo build, etc.) are passed through instantly with zero overhead.
# 1. Compile your blocklists (required — shims check the compiled index)
devscan compile
# 2. Enable shims and patch your shell profile
devscan intercept enable
# 3. Reload your shell
source ~/.zshrcRe-run
devscan intercept enableany time to sync shims — it is safe to run repeatedly and will add any missing shims without affecting existing ones.
# Enable shims and patch shell profile
devscan intercept enable
# Disable and clean up
devscan intercept disable
# Check which shims are active and whether the shims dir is on PATH
devscan intercept status╔══════════════════════════════════════════════════════════════════════╗
║ DEVSCAN BLOCKED ║
╚══════════════════════════════════════════════════════════════════════╝
[MALWARE] chai-utils-test@4.5.3
Found in: malwareDatabase_js.json
npm install was blocked. Remove this package from your command and try again.
Run `devscan audit` for a full vulnerability report.
The warning is printed to stderr in red so it stands out from the surrounding install output. The process exits 1, preventing the install from proceeding.
devscan update automatically rewrites shims to point at the new binary. If a new package manager is added in a future release, re-run devscan intercept enable to write the new shims — it is idempotent and safe to run at any time.
Both explicit installs and lockfile installs are scanned. Lockfile commands (npm ci, bun install, composer install, composer update, go get) read the lock file from the current directory and check every pinned package before the real command runs.
| Manager | Command intercept |
|---|---|
| npm | npm install, npm i, npm add, npm ci (lockfile) |
| pnpm | pnpm add, pnpm install (lockfile) |
| bun | bun add, bun install (lockfile) |
| pip | pip install, pip3 install |
| cargo | cargo add, cargo install |
| go | go get, go install, go.sum (lockfile) |
| composer | composer require, composer install, composer update (lockfile) |
| code / code-insiders | code --install-extension, code-insiders --install-extension |
VS Code extensions are an increasingly common attack surface. Malicious publishers clone popular extension names, slip through the marketplace review process, and execute arbitrary code on install or activation. devscan addresses this in two ways: auditing what you already have installed, and blocking malicious extensions before they land.
devscan automatically enumerates extensions across all VS Code-family editors on your machine:
- VS Code —
~/.vscode/extensions/ - VS Code Insiders —
~/.vscode-insiders/extensions/ - Cursor —
~/.cursor/extensions/ - VSCodium —
~/.vscode-oss/extensions/
Extensions from all detected editors are merged and deduplicated. Run a full audit:
# Audit all installed extensions across every VS Code variant
devscan audit --global --ecosystem vscode
# List every installed extension with version and path
devscan list --global --ecosystem vscode
# Full health check including extensions
devscan doctor --globalExtensions are checked against OSV.dev (using the VSCode ecosystem) and your local blocklists — the same pipeline used for npm, pip, and cargo packages. OSV's VSCode ecosystem is valid but sparsely populated today; blocklists are the primary coverage layer for now. Any finding is reported with severity, advisory ID or blocklist source, and the extension path.
When intercept shims are enabled, code --install-extension is intercepted before the extension is fetched:
# 1. Add known-bad publishers/extensions to your blocklist
# (see Blocklists section for format)
# 2. Compile the blocklist
devscan compile
# 3. Enable shims — writes shims for `code`, `code-insiders`, and `codium`
devscan intercept enable
# 4. Reload your shell
source ~/.zshrcAfter that, any attempt to install a blocklisted extension via the CLI is stopped:
╔══════════════════════════════════════════════════════════════════════╗
║ DEVSCAN BLOCKED ║
╚══════════════════════════════════════════════════════════════════════╝
[CRITICAL] malicious-publisher.fake-copilot
Found in: vscode-blocklist.csv
code --install-extension was blocked. Remove this extension from your command and try again.
Add a CSV to ~/.devscan/resources/ with Ecosystem set to vscode and Name as publisher.extensionname:
Ecosystem,Name,Version,Reason
vscode,malicious-publisher.fake-copilot,,MALWARE
vscode,badactor.crypto-stealer,1.0.0,MALWARE
Omit Version to block all versions of that extension. Then recompile:
devscan compileThe VS Code Extensions panel does not invoke the code binary, so shims cannot intercept GUI installs. devscan's post-install audit (devscan audit --global --ecosystem vscode) is the defence for that path — run it after installing extensions from the marketplace, or schedule it in CI.
Search OSV.dev for advisories directly from the terminal — faster and more scriptable than the OSV web UI.
# All advisories for a package (all ecosystems)
devscan osv --package axios
# Scoped to a specific ecosystem
devscan osv --package axios --ecosystem npm
# Only advisories affecting a specific version
devscan osv --package axios --version 1.2.3
devscan osv --package requests --ecosystem pypi --version 2.28.0Direct lookup by CVE, GHSA, RUSTSEC, PYSEC, or any OSV ID:
devscan osv CVE-2024-1234
devscan osv GHSA-xxxx-yyyy-zzzz
devscan osv RUSTSEC-2024-0001Searches for the term as a package name across all ecosystems, then filters results where the term appears in the advisory ID, summary, details, or package name:
devscan osv "onering"
devscan osv "prototype pollution" --ecosystem npmBy default results show a one-line summary per advisory. Use --detail to expand full advisory text, all affected version ranges, and references:
devscan osv --package lodash --detail
devscan osv CVE-2024-1234 --detailOutput can be saved as HTML, Markdown, or JSON — format is inferred from the file extension:
devscan osv --package axios --output report.html
devscan osv --package axios --output report.md
devscan osv --package axios --output report.json
# Or specify format explicitly
devscan osv --package axios --html
devscan osv --package axios --json
devscan osv --package axios --md
# Detail mode in a saved report
devscan osv --package axios --detail --output report.htmlPass the short name — devscan maps it to the OSV ecosystem name automatically:
| Flag value | OSV ecosystem |
|---|---|
npm |
npm |
pypi |
PyPI |
cargo, crates.io, rust |
crates.io |
go |
Go |
gem, ruby |
RubyGems |
composer, packagist, php |
Packagist |
Network results are cached locally to keep scans fast.
| Data | TTL | Location (macOS) |
|---|---|---|
| Vulnerability advisories (OSV.dev) | 1 hour | ~/Library/Caches/devscan/ |
| Runtime latest versions | 7 days | ~/Library/Caches/devscan/versions/ |
On Linux: ~/.cache/devscan/ · On Windows: %LocalAppData%\devscan\
Force a fresh lookup at any time:
devscan doctor --no-cachePlace .devscan.json in your project root or home directory:
{
"ignore": ["left-pad"],
"severity_threshold": "medium",
"ecosystems": ["npm", "pypi"],
"auto_fix": false
}| Ecosystem | Runtime | Packages | Vulnerabilities |
|---|---|---|---|
| Node.js / npm | ✓ | ✓ | ✓ via OSV.dev |
| Bun | ✓ | ✓ (via npm) | ✓ via OSV.dev |
| Python / pip | ✓ | ✓ | ✓ via OSV.dev |
| PHP / Composer | ✓ | ✓ | ✓ via OSV.dev |
| Rust / Cargo | ✓ | ✓ | ✓ via OSV.dev |
| Go modules | ✓ | ✓ (project) | ✓ via OSV.dev |
| Ruby / Gem | ✓ | ✓ | ✓ via OSV.dev |
| Homebrew | — | ✓ | ✓ via OSV.dev |
| VS Code extensions | — | ✓ (blocklist only) | ✓ via local blocklists; OSV VSCode ecosystem exists but has no data yet |
| Git | ✓ | — | — |
Vulnerability data is sourced from OSV.dev — an open, community-driven vulnerability database covering npm, PyPI, Go, crates.io, Packagist, RubyGems, and more.
Large scans (1000+ packages) are automatically chunked into batches to stay within OSV API limits.
devscan ships a Claude Code skill that lets AI agents run devscan against any project — auditing vulnerabilities, scanning for secrets, checking outdated packages, and generating reports.
Install the skill once:
devscan install-skillThis copies the skill into ~/.claude/skills/run-devscan/, making /run-devscan available in every project in every Claude Code session.
Once installed, Claude can run commands like:
audit this project for vulnerabilities
scan for exposed secrets
check for outdated dependencies
generate an HTML report
look up GHSA-29mw-wpgm-hmr9
The skill source lives at cmd/skills/run-devscan/ and is embedded directly in the binary — no separate download needed.
devscan/
cmd/ # CLI commands (Cobra)
internal/
detectors/ # Runtime detection (node, bun, python, git, php, rust, go)
inspectors/ # Package inspection (npm, pip, composer, cargo, gomod, vscode extensions)
advisory/ # Vulnerability lookups (OSV.dev + local blocklists) with 1hr cache
intercept/ # Package manager shims — pre-install supply-chain blocking
intercept/managers/ # Per-manager argument parsing (npm, pip, cargo, bun)
versions/ # Runtime latest-version checks with 7-day cache
keyscanner/ # Secret and API key detection (file-based pattern scanning)
sysinfo/ # OS, chip, and architecture detection
traverse/ # Sub-project discovery by manifest files
output/ # Terminal renderers (table, JSON, compact)
report/ # Export renderers (Markdown, HTML, JSON)
schema/ # Shared types
The JSON output schema is the central contract. The CLI, and future TUI and GUI layers, are all thin wrappers on top of it.
- Runtime latest-version checks — Go, Node, Bun, Python, PHP, Rust, Git
- Fix commands for all supported ecosystems
- Sub-project traversal with
--depth - Filesystem paths for vulnerable packages
- System info in reports (OS, chip, arch)
- HTML and Markdown report export
- Ruby / gem support
- Homebrew package inspection
- Secret and API key scanning (
devscan keyscan) -
--include-keysflag to add secrets section to full reports - Local blocklist support — CSV and JSON supply-chain attack databases (
~/.devscan/resources/) -
devscan compileto merge blocklists into a fast single index -
devscan update-dbto fetch latest databases from Aikido Intel and recompile - Pre-install intercept shims for npm, pip, cargo, bun, go, composer (
devscan intercept) - Intercept: lockfile scanning for
npm ci,bun install,composer install/update,go get - User advisories — flag compromised packages immediately via
.devscan/advisories.yamlwithout waiting for OSV -
devscan osv— search OSV by package name, version, advisory ID, or keyword; export as HTML/Markdown/JSON - Claude Code skill —
devscan install-skillinstalls/run-devscaninto~/.claude/skills/for AI-assisted scanning in any project - VS Code extension scanning — audit installed extensions across VS Code, Insiders, Cursor, and Codium against OSV (
VSCodeecosystem) and local blocklists - VS Code extension intercept —
code --install-extensionshim blocks malicious extensions before install - System package managers — dpkg (Debian/Ubuntu), rpm (Fedora/RHEL), apk (Alpine)
- Baseline diff (
--compare baseline.json) - CI summary output (GitHub Actions annotations)
-
--ignoreflag to suppress known/accepted advisories
MIT