{"slug": "pkgxray-inspect-what-gets-installed-not-what-executes", "title": "Pkgxray – inspect what gets installed, not what executes", "summary": "Pkgxray, a pre-install security tool for npm packages, MCP servers, and AI agents, uses static analysis to inspect packages before installation, reporting SAFE, REVIEW, or BLOCK verdicts without executing code. The tool, which can block a sample modeled on the 2024 @solana/web3.js compromise, addresses the 454,648 malicious open-source packages identified in 2025, with 99.8% of Q4 malware originating from npm, according to Sonatype.", "body_md": "**pkgxray — pre-install security for npm packages, MCP servers, and AI agents.**\n\nUse local, zero-dependency package static analysis to inspect npm packages and\nModel Context Protocol (MCP) servers before installation or connection. pkgxray\nreports cited `SAFE`\n\n, `REVIEW`\n\n, or `BLOCK`\n\nevidence without executing package\ncode during normal scans.\n\n**Static analysis** · **Supply-chain intelligence** · **Prompt-injection detection** ·\n**MCP security** · `SAFE`\n\n/ `REVIEW`\n\n/ `BLOCK`\n\nReal runs: guard clears express@4.21.0, then blocks a sample modeled on\nthe 2024 @solana/web3.js compromise.\n\n[▶ 60-second walkthrough](#demo)\n\n```\nnpx --yes pkgxray@1.0.4 guard npm:express@4.21.0\n```\n\nThis downloads pkgxray through npm's temporary `npx`\n\ncache, stages the target\ntarball in quarantine, and performs the static and supply-chain checks. It does\nnot globally install pkgxray, run `npm install`\n\n, execute lifecycle scripts, or\nexecute package code.\n\n```\nDecision: **SAFE**\nGrade: **A+** (99/100)\n\nNo high- or medium-risk indicators were found in the provided evidence.\n\nNotes:\n- **INFO npm-vs-github-clean** — npm tarball matches the linked GitHub repo\n  at the published version. (15/16 files match GitHub @4.21.0)\n…\n```\n\nReal output, abridged. A BLOCK verdict instead lists every finding with\nthe file and evidence that produced it.\n\nPoint it at a package, get a verdict with cited evidence — before a single\nline of that package runs. `guard`\n\nstages the package in a sandboxed\nquarantine, audits the staged copy, and only promotes it when policy allows.\nIt never runs `npm install`\n\n, lifecycle scripts, build steps, or package code.\n\n| Verdict | Exit | Meaning |\n|---|---|---|\n`SAFE` |\n`0` |\nNo high- or medium-risk indicators were found; default policy permits promotion. |\n`REVIEW` |\n`3` |\nEvidence is incomplete or a privileged capability needs human review. |\n`BLOCK` |\n`2` |\nHigh-severity cited evidence requires rejection or deep investigation. |\n\n`SAFE`\n\nis not a proof that a package is harmless; static analysis cannot see a\npayload downloaded only at runtime. See the [threat model](/adamsjack711-ux/pkgxray/blob/main/docs/threat-model.md).\n\nFrom a repository checkout:\n\n```\nnpx --yes pkgxray@1.0.4 --file examples/onboarding-malicious.json --format markdown\n```\n\nThe fixture contains inert source text that models a split-string SSH-key read\nand network exfiltration. It is never executed. The command returns `BLOCK`\n\n(exit `2`\n\n) and cites the matching file and evidence.\n\n[Scan pull requests and schedule dependency rechecks](/adamsjack711-ux/pkgxray/blob/main/docs/reference.md#monitoring-pkgxray-recheck).[Expose pkgxray's tools to an MCP-capable coding agent](/adamsjack711-ux/pkgxray/blob/main/docs/mcp.md#the-pkgxray-mcp-server).[Evaluate the experimental Hookshot install gate](/adamsjack711-ux/pkgxray/blob/main/examples/hookshot).\n\nAI coding assistants install packages and connect to MCP servers at machine\nspeed, often without a human ever reading the code. Sonatype reported\n**454,648 newly identified malicious open-source packages across monitored\necosystems in 2025**. Its Q4 report counted 394,877 in that quarter and said\n99.8% of Q4 malware originated from npm\n([annual figure](https://www.infosecurity-magazine.com/news/454000-malicious-open-source/);\n[Q4 scope](https://www.sonatype.com/blog/open-source-malware-index-q4-2025-automation-overwhelms-ecosystems)).\nTraditional antivirus inspects what *executes*; **pkgxray inspects what gets\ninstalled**.\n\n`npm audit`\n\nand OSV-Scanner answer an essential question — *does this package\nhave a known CVE?* — and pkgxray asks it too (via OSV, before anything\ndownloads). But a freshly trojaned package has no CVE yet, so pkgxray also\nanalyzes **trust**: what the code actually does, whether the published npm\nartifact matches the tagged GitHub source, whether the provenance attestation\nis consistent with the claimed repository, and whether the docs carry a\nprompt-injection payload aimed at the agent reading them.\n\nIt is intentionally conservative: verdicts come from deterministic heuristics\n(no LLM in the verdict path, so injected text can't steer them), only\ncitable evidence is reported, and the **zero-heuristic-false-block calibration\non the top-1000 most-downloaded packages** is\n[regression-gated in CI](/adamsjack711-ux/pkgxray/blob/main/docs/benchmark.md). That claim is scoped to the\nmost-installed set — it is *not* a claim of zero false blocks on every package;\nthe newer MCP/agent-tooling ecosystem is over-blocked and being reconciled\nper-case ([details](/adamsjack711-ux/pkgxray/blob/main/docs/benchmark.md#scope-of-the-claim-read-this-first)).\n\n| Threat | Coverage | How pkgxray sees it |\n|---|---|---|\n| Credential theft | ✅ | reads of `.ssh` / `.aws` / `.npmrc` / `.env` / keychains / wallets, incl. split-fragment paths (`\".s\"+\"sh\"` ) |\n| Prompt injection | ✅ | tiered detection in docs, comments, metadata; deterministic verdict path can't be steered |\n| Unicode smuggling | ✅ | invisible tag-block characters + Trojan Source bidi / zero-width |\n| Base64 payloads | ✅ | encoded envelopes in docs/comments; blobs decoded into computed-arg `eval` / `new Function` / `child_process` |\n| Exfiltration & loaders | ✅ | cross-file correlation: stage-2 loaders, `curl | sh` , `process.env` harvesting near a network sink, EtherHiding |\n| Persistence | ✅ | writes to shell rc files, cron, launch agents |\n| Obfuscation | ✅ | packed blob + computed-arg execution; minification alone is deliberately not flagged |\n| Known CVEs | ✅ | OSV batch pre-check before download; never mutable by config |\n| Trojaned updates / maintainer takeover | ✅ | `recheck` verdict-drift + version-drift monitoring |\n| Artifact divergence | ✅ | published npm tarball diffed against the tagged GitHub source |\n| MCP capability abuse | ✅ | capability-surface mismatch in the manifest audit (a `get_weather` that also takes a `command` ) |\n| Runtime tool drift | ✅ | `mcp-proxy` re-audits on `tools/list_changed` ; pinned-manifest drift is denied |\n| Sequence-level tool-call chains | ◑ | `mcp-proxy` gates each call and scans results; no cross-call flow analysis —\n|\n| Dependency confusion / typosquats | ◑ | callback beacons, repo-mismatch and provenance-mismatch signals; no name-similarity heuristic |\n\n✅ detected · ◑ partial / indirect\n\n**Known blind spot:** pkgxray reasons about bytes in the tarball. A package\nthat downloads its real payload *after* install can ship a clean tree —\npkgxray flags the capability when its shape is unambiguous, but pair it with\nruntime sandboxing when that risk matters. Full analysis:\n[docs/threat-model.md](/adamsjack711-ux/pkgxray/blob/main/docs/threat-model.md).\n\n**Continuous monitoring**—diffs installed deps against a stored verdict baseline and pre-vets newer versions`pkgxray recheck`\n\n**MCP vetting**—`pkgxray mcp`\n\naudits a server's tool manifest before you connect;`--pin`\n\n/`--recheck`\n\ncatch the rug-pull;`pkgxray-mcp`\n\ngives any agent the audit tools directly**Runtime gate**—wraps a live MCP server on the wire: denied tools stripped, ~0.05 µs per-call verdict, injection scan of tool results`pkgxray mcp-proxy`\n\n**Install gate**— a[hookshot](https://github.com/CorridorSecurity/hookshot)hook runs`guard`\n\non every package an agent tries to install, across Claude Code, Cursor, Windsurf, Factory Droid, and Codex ()`examples/hookshot/`\n\n**Policy engine**— one`.pkgxray.json`\n\nread by every surface; tighten freely, every loosening is printed; CVEs can never be allowed away; fail closed**Opt-in behavioral canary**—runs lifecycle scripts in an OS sandbox with decoy credentials; it can`pkgxray canary`\n\n*confirm*malice, never*clear*a package\n\n| Verdict | Meaning | You should |\n|---|---|---|\n🟢 `SAFE` |\nNo high- or medium-risk indicators. | Install. Only `safe` promotes out of quarantine by default. |\n🟡 `REVIEW` |\nIncomplete evidence, or a privileged capability that needs a human. | Inspect the quarantined copy before promoting. |\n🔴 `BLOCK` |\nHigh-severity, cited evidence. | Do not install. Every finding names the file and evidence. |\n\nExit codes are stable and CI-friendly: ** 0** safe/allow ·\n\n**block ·**\n\n`2`\n\n**review. The full signal-to-severity mapping is in the**\n\n`3`\n\n[severity policy](/adamsjack711-ux/pkgxray/blob/main/docs/reference.md#severity-policy-what-lands-in-block--review--info).\n\n**Vet an npm package before installing**\n\n```\npkgxray guard npm:some-package@1.2.3 [--format json]\npkgxray guard ./ext --promote-to ./approved/ext   # local dir, promote if policy allows\n```\n\n**Vet an MCP server before connecting** — full guide: [docs/mcp.md](/adamsjack711-ux/pkgxray/blob/main/docs/mcp.md)\n\n```\npkgxray mcp --package npm:some-mcp-server@1.4.2 npx some-mcp-server\npkgxray mcp --recheck npx some-mcp-server   # catch the rug-pull\n```\n\n**Enforce in CI/CD**\n\n```\npkgxray audit package-lock.json [--deep]    # also: yarn.lock, pnpm-lock.yaml, package.json\nnpx pkgxray recheck package-lock.json       # scheduled: exits non-zero only on a regression\n```\n\nA ready-made [GitHub Actions integration](/adamsjack711-ux/pkgxray/blob/main/docs/integrations/github-actions.md)\nand the self-hostable cache server (`PKGXRAY_CACHE_URL`\n\n) are documented in the\n[reference](/adamsjack711-ux/pkgxray/blob/main/docs/reference.md#monitoring-pkgxray-recheck).\n\n**Guard AI coding agents**\n\npkgxray is published on the [MCP Registry](https://registry.modelcontextprotocol.io)\nas `io.github.adamsjack711-ux/pkgxray`\n\n. Add it to any MCP client — locally\ninstalled (`pkgxray-mcp`\n\n) or zero-install via `npx`\n\n:\n\n```\n{\n  \"mcpServers\": {\n    \"pkgxray\": {\n      \"command\": \"npx\",\n      \"args\": [\"--yes\", \"--package\", \"pkgxray@1.0.4\", \"pkgxray-mcp\"],\n      \"env\": { \"PKGXRAY_MCP_ALLOWED_ROOTS\": \"/absolute/path/to/project\" }\n    }\n  }\n}\n```\n\nThe [MCP guide](/adamsjack711-ux/pkgxray/blob/main/docs/mcp.md#the-pkgxray-mcp-server) explains the operator-owned\nfilesystem boundary. Product-specific setup is in the\n[coding-agent integration guide](/adamsjack711-ux/pkgxray/blob/main/docs/integrations/coding-agents.md). Gate\ninstalls with the [Hookshot integration](/adamsjack711-ux/pkgxray/blob/main/examples/hookshot) and wrap MCP servers with\n[ pkgxray mcp-proxy](/adamsjack711-ux/pkgxray/blob/main/docs/mcp.md#per-call-runtime-gate-pkgxray-mcp-proxy).\n\nOne optional `.pkgxray.json`\n\n, read by every surface. Zero config means\nmaximum strictness.\n\n```\n{\n  \"policy\": \"safe-only\",              // or \"allow-review\" (a loosening — warns)\n  \"failOn\": \"review\",                 // CI exit threshold\n  \"scanErrorPolicy\": \"fail-closed\",   // a scan that errors → review, never safe\n\n  \"allow\": [\n    { \"pkg\": \"left-pad@1.3.0\", \"sha256\": \"e0b0…\",\n      \"reason\": \"reviewed 2026-07\", \"expires\": \"2026-10-01\" }\n  ]\n}\n```\n\nPrecedence, `mute`\n\n/ `mcp`\n\nblocks, and enforced invariants:\n[docs/configuration.md](/adamsjack711-ux/pkgxray/blob/main/docs/configuration.md) ·\n`.pkgxray.example.json`\n\nThe 60-second walkthrough — the SAFE run, the blocked trojan with its exit code, then a lockfile audit:\n\n## pkgxray-demo.mp4\n\nAll captures are real runs — reproduction steps in\n\n`docs/screenshots/`\n\n, which also shows the\nMCP proxy, hookshot install gate, and browser extension in action.`npm audit`\n\nand [OSV-Scanner](https://google.github.io/osv-scanner/) match\ndependencies against known CVEs — a different question, answered well.\npkgxray is designed to run *alongside* them, not replace them (it queries OSV\nitself, before anything downloads). The comparison that matters is against\ntools in the same lane — behavioral supply-chain vetting:\n\n| Capability | Socket.dev | OpenSSF Package Analysis | Cisco MCP Scanner | pkgxray |\n|---|---|---|---|---|\n| Fully local, zero-dependency, no account or cloud upload | — ¹ | ◑ ² | ◑ ³ | ✅ |\n| Static behavior analysis of package code | ✅ | ✅ | ✅ | ✅ |\n| Sandboxed execution (dynamic analysis) | — | ✅ ⁴ | ◑ (optional Docker) | ◑ (opt-in `canary` ) ⁴ |\n| npm ↔ GitHub artifact divergence | unknown | — | — | ✅ |\n| Deterministic verdict path — no LLM an injection can steer | — ⁵ | ✅ | ◑ ⁵ | ✅ |\n| Pre-install gate with a quarantined copy to review | ◑ ⁶ | — | — | ✅ |\n| MCP server vetting before connect | — ⁷ | — | ✅ | ✅ |\n| Per-call runtime gating of live MCP traffic | — | — | — ⁸ | ✅ (`mcp-proxy` ) |\n| Verdict-drift monitoring vs. a stored baseline | ✅ (cloud-side) | — | — | ✅ (local `recheck` ) |\n\nComparison made 2026-07-21 against each tool's public documentation;\nunknown means not publicly documented — not verified either way.\n\n¹ Socket's analysis runs in its cloud; Socket Firewall needs no account but consults Socket's hosted intelligence on every install. ² Open source and self-hostable, but built as a registry-scale analysis pipeline (Docker/gVisor), not an install-time developer gate. ³ The YARA analyzer runs locally; the LLM-as-judge and Cisco AI Defense analyzers require API keys. ⁴ Both detonate packages in an OS sandbox. pkgxray's opt-in\n\n[runs two phases — install-time lifecycle scripts and the import of the package entry point — with decoy credentials, so the malicious-on-first-](/adamsjack711-ux/pkgxray/blob/main/docs/canary-threat-model.md)\n\n`canary`\n\n`require`\n\n(flatmap-stream) shape that is\npkgxray's stated [blind spot](/adamsjack711-ux/pkgxray/blob/main/docs/threat-model.md#known-blind-spot)is triggered and observed. Egress is now kernel-confined on both platforms:\n\n`sandbox-exec`\n\non macOS and, on Linux with `bubblewrap`\n\n+ `iproute2`\n\n, a private\nnetwork namespace (`bwrap+netns`\n\n) where a raw-socket dial that bypasses the\nproxy is refused by the kernel (`ENETUNREACH`\n\n) while proxied egress is still\ncaptured. That tier engages only after a runtime\n[self-test proves it](/adamsjack711-ux/pkgxray/blob/main/docs/canary-threat-model.md#isolation-levels)in the environment (verify with\n\n`node scripts/verify-netns-confinement.js`\n\n); absent the\ntooling it falls back to observe-only and says so. Still ◑ — not for a\nconfinement gap, but by design: canary is opt-in and confirm-only (it proves\nmalice, never clears a package) and detonates without the package's\ndependencies installed, whereas OpenSSF Package Analysis runs registry-scale and\ndefault-on. Run them as complements — pkgxray before install, full dynamic\nanalysis where that risk matters.\n⁵ Socket's LLM-based code inspection is a headline feature\n(“AI-detected potential malware”, human-confirmed); Cisco's YARA-only mode\nis deterministic, its LLM analyzer is not.\n⁶ Socket Firewall blocks risky packages at install time; it does not stage a\nquarantined copy for human review.\n⁷ Socket's MCP offering exposes its package-scoring API to agents; it does\nnot vet arbitrary MCP servers at connect time.\n⁸ Cisco MCP Scanner is analysis-only per its docs — it does not proxy or gate\nlive MCP traffic.Acquisition (OSV pre-check → fetch) → sandboxed quarantine → static analysis → policy → verdict. The same engine backs every surface: CLI, MCP server, runtime proxy, install hook, browser extension, and CI cache server. Principles: never execute untrusted code · citable evidence only · minimize false positives · fail closed · zero runtime dependencies.\n\nDetails: [docs/architecture.md](/adamsjack711-ux/pkgxray/blob/main/docs/architecture.md) ·\n[docs/design.md](/adamsjack711-ux/pkgxray/blob/main/docs/design.md)\n\n**Local static analysis: ~25 ms**— a full guard of`express`\n\nis ~1.3–1.5 s cold-cache, almost all network round-trips (Apple M1, Node 26)**Known-vulnerable packages block at the OSV pre-check**, before download** Calibration**(precision, recall, the 0-heuristic-false-block gate on the top-1000 most-downloaded —[scope](/adamsjack711-ux/pkgxray/blob/main/docs/benchmark.md#scope-of-the-claim-read-this-first)) is measured by a committed[benchmark corpus](/adamsjack711-ux/pkgxray/blob/main/benchmark)that fails CI when it regresses\n\nFull numbers: [docs/reference.md#performance](/adamsjack711-ux/pkgxray/blob/main/docs/reference.md#performance) ·\nmethodology: [docs/benchmark.md](/adamsjack711-ux/pkgxray/blob/main/docs/benchmark.md)\n\n| Doc | What it covers |\n|---|---|\n|\n\n[threat-model.md](/adamsjack711-ux/pkgxray/blob/main/docs/threat-model.md)[mcp.md](/adamsjack711-ux/pkgxray/blob/main/docs/mcp.md)[mcp-registry.md](/adamsjack711-ux/pkgxray/blob/main/docs/mcp-registry.md)[configuration.md](/adamsjack711-ux/pkgxray/blob/main/docs/configuration.md)`.pkgxray.json`\n\nschema and invariants[reference.md](/adamsjack711-ux/pkgxray/blob/main/docs/reference.md)`recheck`\n\n, JSON output, cache server[benchmark.md](/adamsjack711-ux/pkgxray/blob/main/docs/benchmark.md)[compatibility.md](/adamsjack711-ux/pkgxray/blob/main/docs/compatibility.md)[json-schema.md](/adamsjack711-ux/pkgxray/blob/main/docs/json-schema.md)`--format json`\n\nschemaStart at the [documentation index](/adamsjack711-ux/pkgxray/blob/main/docs/README.md). Longer-term plans:\n[project status](/adamsjack711-ux/pkgxray/blob/main/docs/project-status.md), [adoption playbook](/adamsjack711-ux/pkgxray/blob/main/docs/adoption.md),\nand GitHub issues.\n\n```\nnpm test                 # zero-dep node --test suite\nnpm run benchmark        # calibration corpus: precision/recall + 0-false-block gate\nnpm run build:browser    # build the MV3 browser extension\n```\n\nContributions are welcome; read [CONTRIBUTING.md](/adamsjack711-ux/pkgxray/blob/main/CONTRIBUTING.md) and the\n[Code of Conduct](/adamsjack711-ux/pkgxray/blob/main/CODE_OF_CONDUCT.md) before opening a pull request.\n\nReleases are published to npm with provenance (SLSA attestation), gated on the\ntest suite, the calibration benchmark, and pkgxray's own supply-chain guard.\nTo report a vulnerability in pkgxray itself, see [SECURITY.md](/adamsjack711-ux/pkgxray/blob/main/SECURITY.md).", "url": "https://wpnews.pro/news/pkgxray-inspect-what-gets-installed-not-what-executes", "canonical_source": "https://github.com/adamsjack711-ux/pkgxray", "published_at": "2026-07-22 12:31:02+00:00", "updated_at": "2026-07-25 20:02:37.130814+00:00", "lang": "en", "topics": ["ai-safety", "ai-agents", "developer-tools"], "entities": ["pkgxray", "npm", "Sonatype", "Model Context Protocol", "OSV-Scanner", "express@4.21.0", "@solana/web3.js"], "alternates": {"html": "https://wpnews.pro/news/pkgxray-inspect-what-gets-installed-not-what-executes", "markdown": "https://wpnews.pro/news/pkgxray-inspect-what-gets-installed-not-what-executes.md", "text": "https://wpnews.pro/news/pkgxray-inspect-what-gets-installed-not-what-executes.txt", "jsonld": "https://wpnews.pro/news/pkgxray-inspect-what-gets-installed-not-what-executes.jsonld"}}