Scan npm & PyPI packages
Scan a package and its whole dependency tree for malware and known vulnerabilities before installing it, or audit what's already in node_modules and your virtualenvs.
On this page
beam add package checks an npm or PyPI package before it reaches your project, the way beam add skill checks a skill. It fetches the package and every dependency into a temporary folder, scans them all, and installs only if nothing critical turns up. beam packages scan runs the same checks on packages you've already installed. Both are useful when an AI coding assistant wants to install a package it named itself.
Add a package
beam add package zod # npm: scan zod and its dependencies, then install the scanned version
beam add package [email protected] -D # a dev dependency
beam add package requests==2.32.3 --pip # PyPI, installed with pip
beam add package some-cli -g --scan-only # report only; install nothing
The package must be a registry name with an optional version, tag or range. Git URLs, tarball URLs and local paths are refused because they can't be pinned to what was scanned. If the scan passes, Beam installs the exact version it scanned. It uses your project's own package manager, detected from the lockfile: npm, pnpm, yarn or bun. With --pip, Beam installs with python3 -m pip, or with the interpreter you pass to --python. -g installs globally with npm, or with pip's --user.
Nothing runs during the scan
npm packages are fetched with --ignore-scripts, so no lifecycle script from any package in the tree runs. Python packages are fetched as wheels only, because building a source distribution runs its setup.py, and that's the code under suspicion. When a package ships source only, Beam downloads its sdist straight from PyPI. It checks the file against the hash PyPI publishes and unpacks it without building it. In that case the package's own dependencies aren't resolved, and the output says so.
What it looks for
The checks look for the shapes real supply-chain malware takes. Ordinary library code uses eval, child_process, fetch and process.env constantly, so none of those count on their own.
| Check | Example |
|---|---|
| Install-time code | preinstall, install and postinstall scripts, and the files they run |
| Decode and execute | eval(Buffer.from(...)), exec(base64.b64decode(...)) |
| Environment theft | JSON.stringify(process.env) near network calls, or anywhere in install-time code |
| Install-time beacons | hostname or username read and sent out while installing (the dependency-confusion pattern) |
| Data-collection endpoints | Discord or Telegram bot webhooks with tokens, request-capture services |
| Obfuscation | javascript-obfuscator output, long runs of hex-escaped text |
| Credential and wallet files | SSH keys, cloud credentials, browser password stores, wallets; registry tokens in .npmrc count when read at install time |
| Python startup hooks | .pth files that run code on every Python start |
| Dependencies outside the registry | git, URL or file: dependencies |
| Typosquats | names one typo away from a popular package, such as expresss or crossenv |
Combinations decide most critical findings. For example, a typo name on a package first published in the last 30 days is critical, while an old package with a near-miss name only gets a warning.
Known vulnerabilities
When the machine is connected with beam connect, or BEAM_APP_TOKEN is set, every package in the tree is also checked against the advisory database that beam cve check uses. Only package names and versions are sent. Critical advisories, and anything in CISA's Known Exploited Vulnerabilities catalog, count as critical. Without a connection the check is skipped with a note. Use --no-cve to skip it deliberately. See App monitoring and dependency checks for tokens and monthly allowances.
What blocks an install
A critical finding stops the install, and the command exits 2. Review the findings. If you trust the source, --force installs anyway. High and medium findings are warnings, such as a postinstall script, which native addons and tools like esbuild legitimately need. Each package gets a 0–100 risk score and a level from LOW to CRITICAL, computed the same way as for skills. --json prints every scanned package with its findings.
Scan installed packages
beam packages scan . # node_modules (npm, yarn, pnpm, bun) and .venv, venv or env
beam packages scan path/to/pkg # one package folder or a site-packages folder
beam packages scan . --json # flagged packages as JSON, for CI
The scan covers scoped and nested packages and pnpm's .pnpm store. In a virtualenv, it reads the files each distribution's RECORD lists. Only a project's direct dependencies get the typosquat check, since those are the names someone typed. Only flagged packages are printed. The command exits 2 when any package has a critical finding.
Limits
Files over 3 MB, and packages with more than 2,000 files, are scanned only in part, and skipped files are listed. The checks are heuristic: code that builds its strings at runtime can avoid them. Treat a clean result as evidence for your review, not proof that a package is safe, and keep pinning versions with a committed lockfile.
Set this up with your coding agent
Install the agentbeam-setup skill for Claude Code, Codex, Cursor, Gemini CLI, OpenCode and Copilot, then ask your agent to set up AgentBeam on this machine. Beam scans the skill before it installs.
npx -y @agent-beam/beam add skill agentbeam-setup -g --all-agents