The 'check' command
The Check Command is the second pillar of NDM. It performs a static analysis of information from the package.
How to run it?
You first need to install NDM and than run the check command:
ndm check
You will be asked for a package name. After entering a valid name, NDM will ask you which version you would like to analyze. You can choose the most recent version too. After that, the package information will be displayed in the terminal, and you will have to confirm that it is the correct package.
When this part is successfully finished the Check will start:
Check
NDM performs a series of automated security and quality checks on npm packages. Each check is based on real metadata from the npm registry (registry.npmjs.org) and reflects common patterns seen in JavaScript supply chain incidents.
NDM currently implements ten checks, each of which is described in detail below.
Repository Age
NDM evaluates how long a package has existed in the npm registry.
This check uses the time.created field from the registry metadata.
Many malicious packages uploaded to npm are new and only exist for short-term exploitation. NDM gives these packages a "warning level" in repoAge when they are younger than 22 days.
Last Update
NDM evaluates how recently the selected version was modified using the time.modified field.
If the selected version is less than two days old, NDM warns the user.
If the version is between 21 and 51 days old, NDM issues a warning about potential abandonment or unpatched vulnerabilities.
If the version is older than 50 days, NDM marks the package as "critical" in lastupdate.
This matters because new versions aren't tested, and malicious packages are mostly caught within the first 48 hours. Old packages could also contain security vulnerabilities.
Maintainer Changes
Depending on how many exist, NDM checks if the maintainers of the selected version are different from those of the previous 5-10 versions. It sorts the versions by timesteps and then compares the selected version to the next five to ten older versions. NDM also attempts to identify malicious versions by checking if the maintainer data is incomplete.
NDM does not compare maintainers across the entire history. It only compares the selected version with its 5-10 predecessors.
A change in maintainers indicates:
- Account compromise
- ownership transfer
- takeover by unknown actors
However, maintainer changes alone are not a huge signal for a malicious package. It is just one piece of the puzzle.
Snyk Vulnerabilities
NDM queries the Snyk vulnerability database for known CVEs that affect the package. Then, it checks whether the selected version is affected. If something is found, the output will be displayed in the terminal.
Version Vulnerabilities & Deprecation
Version-specific metadata is fetched from the npm registry. The package will be checked for "deprecation" and for any vulnerabilities in the registry.
This is important because we need to use all the information we can get about a package, rather than trusting just one source.
Popularity
The popularity of the selected package is evaluated based on its usage over the last month.
Thresholds:
- Over 5,000,000 downloads → excellent
- Over 500,000 downloads --→ good
- Under 10,000 downloads --→ warning
This matters because packages with low popularity have fewer users watching over the code. However, this doesn't mean that a package with over 5,000,000 downloads per month is safe. For example, Axios was also compromised, despite having about 100,000,000 downloads per week at the time.
Typosquatting Detection
NDM checks if the package name is suspiciously similar to a popular one. NDM also evaluates packages with similar names that have high download numbers.
- Over 500,000 downloads per month → ok
- Over 50,000 downloads a month ---→ warning
- else → critical
Typosquatting is one of the most common attack vectors in NPM. For example, lodash and lodas.
Install Scripts
NDM checks whether the package defines installation scripts, such as:
- preinstall
- install
- postinstall
NDM only checks for the presence of installation scripts. It does not analyze the contents of the scripts.
This is important because an install script can:
- execute arbitrary code
- download binaries
- modify system files
- run shell commands
This is a high-risk vector used in real attacks. NDM flags any installation script as a potential threat, not a guaranteed one.
Dependency Risk
NDM evaluates the number of direct dependencies and direct devDependencies that a package declares.
Thresholds:
- Over 80 -→ critical
- Over 40 -→ warning
- Under 40 → oK
Every dependency is a potential attack surface. Currently, NDM only checks direct dependencies, not the full dependency tree.
Package Size
The unpacked size of the package is checked. For this, the dist.unpackedSize data is used.
Thresholds:
- Over 10,000,000 → critical (10 MB) Only extremely large frameworks or packages containing binary files reach this size. Anything larger than this is highly unusual and may indicate hidden payloads, obfuscated code, or unnecessary files.
- Over 5,000,000 -→ warning (5 MB) Most npm packages are under 1 MB. Large frameworks, such as Next.js, Angular, and Prisma, range from 2–5 MB. Anything over 5 MB is unusual and should be investigated.
- Under → ok This is the typical range for 90% of all npm packages.
This matters because large packages can hide:
- obfuscated code
- unnecessary binaries
- malicious payloads
NDM flags unusually large packages as high-risk.
Scores
After performing these checks, NDM computes two scores.
Risk Score:
The Risk Score measures potential security risk based on the checks performed. To calculate the score, the levels are used to increase or decrease it. Not all checks can result the same minus or plus because some are more important than others.
Health Score:
The Health Score measures package quality. The checks are also used for this. However, some checks are given a different priority here than in the risk score. This is because some checks are more important for the risk score than the health score.