@penumbraforge/vexes
v0.1.1
Published
Cross-ecosystem dependency security scanner. Shakes the tree to see what falls. Zero dependencies.
Downloads
212
Maintainers
Readme
vexes
Cross-ecosystem dependency security scanner. Shakes the tree to see what falls.
Zero dependencies. Pure Node.js. Catches real supply chain attacks.
$ vexes scan
vexes v0.1.0 -- scanning dependencies
Found 847 unique packages across 3 lockfile(s)
~ 847 packages checked in 2.1s (0 cached)
-- CRITICAL --------------------------------------------------
axios 1.14.1 (npm)
GHSA-xxxx -- Remote code execution via compromised dependency
Fixed in: >= 1.14.2
https://osv.dev/vulnerability/GHSA-xxxx
-- HIGH ------------------------------------------------------
lodash 4.17.20 (npm)
GHSA-yyyy -- Prototype pollution in lodash
Fixed in: >= 4.17.21
--------------------------------------------------
2 vulnerabilities . 1 critical . 1 high
in 847 packages across npm, pypi, cargo
completed in 2.1s
--------------------------------------------------What it does
vexes is a dependency security scanner that goes beyond vulnerability databases. It uses a 4-layer detection engine to catch supply chain attacks that signature-based tools miss:
| Layer | Detection Method | What it catches |
|-------|-----------------|----------------|
| 1. AST Analysis | Parses JS/Python source via acorn AST | eval(), child_process.exec(), credential harvesting, obfuscated code, dynamic imports, WebAssembly, setTimeout(string), DNS exfiltration, prototype chain escapes |
| 2. Dependency Graph | Profiles newly added dependencies | Phantom dependencies (brand-new packages), circular staging, typosquatting, Unicode homoglyph attacks |
| 3. Behavioral Fingerprinting | Diffs capability profiles between versions | A utility library that suddenly gains network+exec capabilities |
| 4. Registry Metadata | Analyzes publish history, maintainers, timing | Account takeovers, rapid publishes, dormant package reactivation |
Proven detection
The red team test suite reconstructs 9 real-world attacks and proves vexes catches them:
- axios RAT (March 2026) -- Hijacked maintainer account, hidden dependency with RAT dropper
- Shai-Hulud worm (September 2025) -- Phished credentials, self-replicating worm via chalk/debug
- event-stream (November 2018) -- Social engineering, encrypted payload targeting bitcoin wallets
- ua-parser-js (October 2021) -- Account hijack, cryptominer + password stealer
- litellm/TeamPCP (March 2026) -- CI/CD compromise, 3-stage payload with K8s lateral movement
- Typosquatting --
expresss,loadash,reqeustsand similar name confusion attacks - Novel/hypothetical attacks -- WASM-based payloads, DNS exfiltration, capability escalation
Installation
# Global install
npm install -g @penumbraforge/vexes
# Or run directly
npx @penumbraforge/vexes scan
# Or clone and run
git clone https://github.com/penumbraforge/vexes.git
cd vexes && node bin/vexes.js scan --path /your/projectRequirements: Node.js >= 22.5.0 (uses native SQLite for caching, native fetch)
Commands
vexes scan -- Vulnerability scanning
Enumerates dependencies from lockfiles, queries OSV.dev, and reports known vulnerabilities.
vexes scan # Scan current directory
vexes scan --path ./my-project # Scan a specific directory
vexes scan --ecosystem npm # Scan only npm dependencies
vexes scan --severity critical # Only show critical vulnerabilities
vexes scan --fix # Show upgrade commands for each vuln
vexes scan --json # Machine-readable JSON output
vexes scan --cached # Use cached results (skip freshness check)Ecosystems supported: npm (package-lock.json, pnpm-lock.yaml, yarn.lock), PyPI (Pipfile.lock, poetry.lock, requirements.txt, pyproject.toml), Cargo (Cargo.lock), Go (go.sum), Ruby (Gemfile.lock), PHP (composer.lock), NuGet (packages.lock.json), Java (gradle.lockfile, pom.xml), Homebrew (Brewfile.lock.json, Brewfile)
Exit codes: 0 = clean, 1 = vulnerabilities found, 2 = error/incomplete scan
vexes analyze -- Deep behavioral analysis
Goes beyond vulnerability databases. Downloads registry metadata, runs AST analysis on install scripts, profiles behavioral changes between versions.
vexes analyze # Analyze direct dependencies
vexes analyze --deep # Download + AST-inspect actual tarball code
vexes analyze --explain lodash # Detailed breakdown for one package
vexes analyze --strict # Fail on any signal (for CI)
vexes analyze -v # Show all signals including LOW
vexes analyze --json # Machine-readable JSON outputDetection signals:
KNOWN_COMPROMISED-- Package has known OSV vulnerabilitiesMAINTAINER_CHANGE-- Publishing account changed (possible account takeover)POSTINSTALL_SCRIPT-- Has install lifecycle scriptsRAPID_PUBLISH-- Version published suspiciously quickly after previousVERSION_ANOMALY-- Major version jump or dormancy followed by sudden publishTYPOSQUAT-- Name suspiciously similar to a popular packagePHANTOM_DEPENDENCY-- Brand-new dependency added (< 7 days old)CIRCULAR_STAGING-- New dep published by the same account as the parentCAPABILITY_ESCALATION-- Package gained dangerous capabilities between versionsAST_DANGEROUS_PATTERN-- Dangerous code patterns in install scriptsTARBALL_DANGEROUS_PATTERN-- Dangerous patterns in actual package source codeHOMOGLYPH-- Package name contains suspicious Unicode (zero-width chars, RTL override, non-ASCII)MISSING_PROVENANCE-- No Sigstore provenance attestationNO_REPOSITORY-- No source repository link
vexes fix -- Verified fix recommendations
Finds vulnerabilities and generates verified upgrade commands. Every recommended version is cross-checked against OSV to ensure it isn't itself vulnerable.
vexes fix # Show fix recommendations
vexes fix --json # Machine-readable outputvexes guard -- Pre-install protection
Intercepts npm install and analyzes new/changed packages before they execute. Works by diffing lockfiles -- no network proxy needed.
vexes guard -- npm install axios # Guard a specific install
vexes guard --setup # Install shell wrappers (auto-guard)
vexes guard --uninstall # Remove shell wrappers
vexes guard --force -- npm install # Override HIGH warnings (CRITICAL still blocked)How it works:
- Snapshots current lockfile
- Runs
npm install --package-lock-only --ignore-scripts(dry-run) - Diffs the lockfile to find new/changed packages
- Runs behavioral analysis on those packages
- Blocks if CRITICAL, prompts on HIGH, allows if clean
- Runs the real install only after approval
vexes monitor -- Continuous monitoring
Two modes for CI/CD and development:
# CI mode -- one-shot scan with GitHub Actions annotations
vexes monitor --ci # Default: fail on HIGH+
vexes monitor --ci --severity critical # Only fail on CRITICAL
vexes monitor --ci --sarif # SARIF output for GitHub Advanced Security
vexes monitor --ci --json # Machine-readable JSON
# Watch mode -- continuous local monitoring
vexes monitor --watch # Watch lockfiles + poll OSV hourly
vexes monitor --watch --interval 5 # Poll every 5 minutesGitHub Actions example:
- name: Security scan
run: npx @penumbraforge/vexes monitor --ci --severity high
# Or with SARIF upload to GitHub Advanced Security:
- name: Security scan (SARIF)
run: npx @penumbraforge/vexes monitor --ci --sarif > results.sarif
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifConfiguration
Project config: .vexesrc.json
Place in your project root. Walks up directories to find it.
{
"ecosystems": ["npm", "pypi"],
"severity": "high",
"ignore": [],
"analyze": {
"signals": {
"NO_REPOSITORY": "off",
"POSTINSTALL_SCRIPT": "off"
}
},
"cache": {
"dir": "~/.cache/vexes",
"advisoryTtlMs": 3600000,
"metadataTtlMs": 86400000
},
"output": {
"color": "auto",
"format": "text"
}
}User config: ~/.config/vexes/config.json
Same format. Project config overrides user config.
Allowlists
vexes ships with built-in allowlists for packages with legitimate postinstall scripts (esbuild, sharp, puppeteer, etc.). Signals from these packages are downweighted, not suppressed -- a compromised version still triggers if new dangerous patterns appear.
Architecture
bin/vexes.js CLI entrypoint, command router
src/
cli/
parse-args.js Hand-rolled arg parser (zero deps)
config.js Config loading with prototype pollution protection
output.js Terminal output, ANSI colors, spinner, sanitization
commands/
scan.js Vulnerability scanning via OSV
analyze.js 4-layer behavioral analysis
fix.js Verified fix recommendations
guard.js Pre-install lockfile diffing
monitor.js CI annotations, SARIF output, watch mode
core/
constants.js URLs, thresholds, exit codes
fetcher.js Single-point HTTP with retry/timeout/backoff
logger.js Leveled logger with terminal injection protection
allowlists.js Known-good packages, popular package sets
parsers/
npm.js package-lock.json v1/v2/v3, package.json fallback
pnpm.js pnpm-lock.yaml v6/v9
yarn.js yarn.lock v1 (classic) and v2+ (Berry)
pypi.js requirements.txt (-r recursive), poetry.lock, Pipfile.lock, pyproject.toml
cargo.js Cargo.lock
go.js go.sum
ruby.js Gemfile.lock
php.js composer.lock
dotnet.js packages.lock.json (NuGet)
java.js gradle.lockfile, pom.xml
brew.js Brewfile.lock.json, Brewfile
advisories/
osv.js OSV.dev batch queries, CVSS v3.1 scoring, severity mapping
npm-registry.js npm registry metadata + provenance attestations
pypi-registry.js PyPI JSON API metadata
analysis/
ast-inspector.js Acorn-based AST analysis (JS) + pattern matching (Python)
signals.js Signal orchestrator, composite risk scoring
dep-graph.js Dependency graph profiling, typosquat detection
behavioral.js Capability fingerprinting, version diffing
tarball-inspector.js Tarball download, tar parsing, source inspection
diff.js Lockfile snapshot diffing
provenance.js Sigstore provenance verification
cache/
advisory-cache.js SQLite-backed cache with TTL, corruption recovery
vendor/
acorn.mjs Vendored acorn parser (zero npm deps)
test/
test-ast-inspector.js AST detection + false positive tests
test-behavioral.js Behavioral profiling + diffing
test-cache.js SQLite cache, TTL, corruption resilience
test-dep-graph.js Typosquat detection
test-parse-args.js Argument parser
test-parsers.js All lockfile/manifest parsers
test-redteam.js 9 real-world attack reconstructions
test-robustness.js Input validation, edge cases, securitySecurity design principles
Fail loud, not clean. A security scanner that silently reports clean on failure is worse than useless. If queries fail, vexes exits with code 2 and prints
SCAN INCOMPLETE. Invalid ecosystems are rejected outright instead of silently scanning nothing.Zero dependencies. The dependency chain is the attack surface. vexes has none. Acorn is vendored. SQLite is Node.js built-in.
Terminal injection protection. All external data is sanitized with a comprehensive filter covering CSI sequences (with intermediate bytes), OSC (BEL and ST terminators), DCS/APC/PM/SOS sequences, C1 control codes (0x80-0x9F), and bare ESC bytes.
Prototype pollution protection. Config file merging rejects
__proto__,constructor, andprototypekeys.Command injection prevention. The guard command uses
execFileSync(no shell) with an allowlist of known package managers. Fix commands are shell-escaped before display. Guard setup resolves the vexes binary path at install time rather than usingnpxat runtime.Gzip bomb + SSRF protection. Tarball downloads enforce streaming size limits, HTTPS-only URLs, and a registry host allowlist to prevent memory exhaustion and SSRF attacks.
Cache integrity. Corrupted entries are auto-deleted. Degraded results are never cached. TTL is clamped to prevent config-based stale data attacks (max 7 days advisory, 30 days metadata).
Never recommend vulnerable fixes. The
fixcommand cross-checks every recommended version against OSV before presenting it.Critical signals are undisableable.
KNOWN_COMPROMISED,PHANTOM_DEPENDENCY,CIRCULAR_STAGING, andCAPABILITY_ESCALATIONcannot be turned off via config -- they detect active attacks.Allowlisted packages are still inspected. Known-good packages (esbuild, sharp, etc.) have their signals downweighted, not suppressed. AST analysis runs on all packages regardless of allowlist status.
Unicode homoglyph detection. Package names are checked for invisible characters (zero-width spaces, BIDI overrides) and non-ASCII homoglyphs that could disguise malicious packages.
Integrity-aware lockfile diffing. Guard detects when a package tarball changes without a version bump by comparing integrity hashes.
License
Apache-2.0
Author
Shadoe Myers (@penumbraforge)
