npm-scan
NPM Supply Chain Scan
Use the bundled scanner to walk a starting directory recursively and inspect JavaScript/TypeScript projects that use npm, pnpm, or yarn.
The script reports three evidence types separately:
declared: the package is referenced inpackage.jsonlocked: the affected version is present in a lockfileinstalled: the affected version exists innode_modules/<package>/package.json
Treat locked or installed as stronger evidence than declared.
When to Use
Use this skill when you have incident details such as:
- package name
- affected exact versions
- affected semver range
- disclosure URL and date
Typical trigger requests:
- "Check whether
axios@1.14.1is installed anywhere under this monorepo." - "Scan this directory recursively for
chalkversions matching<5.6.0." - "Use the latest npm compromise details and tell me if any affected versions are present."
When Not to Use
Do not use this skill when:
- the user wants package remediation, upgrades, or lockfile rewrites rather than detection
- the user needs vulnerability severity scoring, CVE enrichment, or SBOM generation
- the package manager is outside the npm ecosystem
- the target path is a single published package tarball instead of a checked-out folder tree
Trigger Phrases
Positive triggers:
- "scan this repo for affected axios versions"
- "check whether
@scope/pkgis installed anywhere under this folder" - "look for
lodashversions matching>=4.17.0 <4.17.21" - "search all subfolders for a compromised npm package"
Negative triggers:
- "upgrade axios everywhere"
- "generate an SBOM"
- "fix the vulnerability automatically"
- "audit this Python environment"
Required Inputs
Collect these before running the scan:
- Package name, for example
axiosor@scope/pkg - At least one affected version selector:
- exact versions with
--version - semver expressions with
--range
- exact versions with
- Starting folder to scan recursively
Use exact versions when an incident report lists them explicitly. Use ranges when the advisory publishes affected windows such as >=1.2.0 <1.2.5.
Default operating choices:
- starting folder: current directory if the user does not provide one
- output mode: text for human review,
--jsonfor machine consumption - selectors: prefer exact
--versionvalues when the incident names specific compromised releases
Workflow
- Read the incident source and extract the package name, affected versions/ranges, and date.
- Run
scripts/scan_npm_dependency.pyfrom the chosen starting folder. - Review the output by evidence type:
installed: package exists on disk undernode_moduleslocked: package resolves to the affected version in a lockfiledeclared: a manifest references the package, but installation is not proven
- If matches are found, report the project roots and file paths. Keep remediation separate from detection unless the user asks for both.
Script-First Policy
Use the bundled scanner as the primary path. Do not replace it with ad hoc find, awk, perl, or grep pipelines unless the user explicitly asks for a one-off custom investigation that the script cannot cover.
Quick Start
Exact-version incident:
python scripts/scan_npm_dependency.py /path/to/root \
--package axios \
--version 1.14.1 \
--version 0.30.4
Range-based incident:
python scripts/scan_npm_dependency.py /path/to/root \
--package some-package \
--range ">=2.4.0 <2.4.3"
Machine-readable output:
python scripts/scan_npm_dependency.py . \
--package axios \
--version 1.14.1 \
--json
CI-style failure on detection:
python scripts/scan_npm_dependency.py . \
--package axios \
--version 1.14.1 \
--version 0.30.4 \
--fail-on-match
Run the functional tests:
python scripts/test_scan_npm_dependency.py
Script Behavior
The scanner:
- walks the starting directory recursively
- skips common heavy or irrelevant directories such as
.git,node_modules,.yarn/cache, and build output folders - treats each directory containing
package.jsonand/or a supported lockfile as a project root candidate - scans
package-lock.json,npm-shrinkwrap.json,pnpm-lock.yaml, andyarn.lock - checks local
node_modules/<package>/package.jsonwhen present
The scanner supports common npm semver syntax in --range, including exact versions, comparator sets, ||, ^, ~, and x/* wildcards.
For package.json, a declared match is reported when the declared dependency spec itself is affected, can resolve to one of the affected exact versions you supplied, or overlaps with an affected range you supplied.
Installed-package detection is recursive within each discovered project's node_modules, so nested or transitive installs such as node_modules/foo/node_modules/<package> are checked too.
Interpretation Rules
declaredonly: the project references the package, but the currently installed or resolved version is not proven from that evidence alonelocked: the affected version is resolved in the dependency graph captured by the lockfileinstalled: the affected version is currently present on disk innode_modules
If the incident is known to remove or hide evidence after install, still rely on lockfiles even when installed is absent.
Output Contract
When reporting results, include:
- scanned root path
- package name and selectors used
- number of project roots scanned
- matches grouped by
declared,locked, andinstalled - file paths and locators for each match
- any warnings emitted by the scanner
If no matches are found, state that explicitly instead of implying a clean bill of health.
Guardrails
- Do not claim a package is installed based on a
declaredfinding alone. - Treat
lockedandinstalledas evidence, not proof of runtime execution. - Keep the incident source URL and disclosure date in the final report when available.
- If the user asks for "latest" incident details, verify them from the source before scanning.
- Do not auto-remediate or delete packages unless the user asks for remediation work.
- Keep the scan non-destructive: do not modify manifests, lockfiles, or
node_modulesduring detection.
Anti-Patterns
- do not collapse
declared,locked, andinstalledinto a single undifferentiated result - do not skip lockfiles just because
node_modulesis absent - do not assume a root-level
node_modules/<package>check is sufficient for transitive installs - do not rely on one package manager format when the folder tree may contain multiple project types
Troubleshooting
Error: provide at least one --version or --range selector
Cause: the scan was started without affected versions or ranges
Solution: rerun with one or more --version and/or --range arguments
Error: start path does not exist or start path is not a directory
Cause: the root path is wrong or not mounted in the current environment
Solution: verify the absolute path and rerun from a readable directory
Problem: scan finishes with warnings Cause: one or more manifests or lockfiles could not be parsed Solution: inspect the warning paths, confirm file format, and rerun after fixing or excluding the broken project
Problem: only declared matches are found
Cause: the dependency may not currently be installed, or lockfiles may be absent
Solution: treat the result as weaker evidence and inspect install state or lockfiles before escalating
References
references/axios-march-2026.md: example incident extraction based on the March 30-31, 2026 axios compromise disclosed by Aikidoscripts/scan_npm_dependency.py: recursive scanner for npm, pnpm, and yarn projectsscripts/test_scan_npm_dependency.py: functional tests covering positive and negative scan cases
More from asgarth/skills
hive
Hive blockchain CLI skill for hive-tx-cli. Query accounts/content/RC/feed/replies, upload images, and broadcast publish/reply/edit/vote/transfer/community/social/profile/reward/custom-json operations with correct key usage.
3hive-developer
Build and debug Hive blockchain software with `hive-tx` in JavaScript/TypeScript, including node failover, quorum reads, key-safe signing, and status-aware broadcasting for wallet, content, and custom_json flows.
2