Checking for installed npm packages and dependencies

In recent months, there have been a number of high-profile supply-chain attacks on the npm package repository and some key packages.

To make it easier to see whether you are impacted by such a compromise, I've created a quick tool that lets you check whether you have a compromised package installed and what it belongs to.

Actual checks for whether you have been infected (just because you have a compromised version, it does not necessarily mean you've actually run the compromised code in the package) are beyond the scope of a simple checker I'm afraid and you will need to review the information about the attack to know what, if anything, you need to do.

The tool is published here:
https://www.npmjs.com/package/npm-supply-chain-check
You should, of course, do a quick check of the code before running it to make sure you are happy. Note though, that I've locked down the package and its source GitHub to prevent unwanted changes. In addition, the package has no external dependencies at all.

You don't need to install it, you can run it with npx instead if you prefer:

Here is an example of checking against the latest attack:

cd ~/.node-red
npx npm-supply-chain-check axios
npx npm-supply-chain-check axios global

Note that you should check both the local and global locations.

Thanks for the tool, watched a couple of video's last week about this hack and was also interested if this apply to NR or Z2M.

After running your tool it found Axios 1.13.5 installed node-red-admin -> axios.

No sure for me if this is an compromised version I asked Chatgpt if the 1.13.5 version is compromised:

Short answer: No โ€” axios@1.13.5 is not one of the compromised versions.

What actually happened

There was a real supply chain attack on Axios in late March 2026:

  • Attackers compromised an npm maintainer account
  • They published malicious versions:
    • axios@1.14.1
    • axios@0.30.4
  • These versions injected a fake dependency (plain-crypto-js) that installed a remote access trojan (RAT) on install
  • The malicious releases were live for only ~2โ€“3 hours before removal

Do you check for the RAT files -->

OS Path Disguised As
macOS /Library/Caches/com.apple.act.mond Apple system cache
Windows %PROGRAMDATA%\wt.exe Windows Terminal
Linux /tmp/ld.py Generic temp file

Looking at the source code, you seem only to check through the various package.json files and folders.

Yes, this isn't meant to be a comprehensive security tool but rather something that anyone can use, regardless of experience, to do a quick check to see if they may have a problem that should be followed up.

According to the write up, the attack actually cleans up the package.json files leaving the RAT behind. If I understand correctly. So running this script might well give one a false sense of security because the indicators the script checks for have already been cleaned away, leaving the executable behind.

No, I don't think so, it uses npm ls to do the checks which will, I believe, check down the tree regardless of the package.json. The package.json is only used to identify root folders to check (folder contains package.json). Correct me if I'm wrong.

Another reason for using Sentinel's custom package installer. It wont run package scripts unless an Admin confirms he wants to proceed. In the warning message it will ask people to verify the changes and confirm.

Additionally, packages are going to be setup and analyzed in a ephemeral docker container before being added to the node_modules nodered sees. This way the attack surface caused by these scripts, if they are accidentally run, will be limited to the container.

Minor question, does this work on environments without docker, e.g. raspberries? Also how does this work if NR is run inside a docker container? Docker within docker is possible but needs extra configuration step.

If you are asking Allan about his tool, perhaps you could take that to a different thread please?

Otherwise, regarding my simple tool. It should work fine inside a Docker container. You just need to access that containers command line.

Unfortunately this only works on environments with docker.

I designed it to run side by side, but I guess it could work with Docker In Docker if the base NR image supports it.

When I run "npx npm-supply-chain-check" it says that I have to install "npm-supply-chain-check@1.0.0" What is it for and do I have to install it ?

Read the rest of the thread to see what it is for. As I understand it, npx does a temporary install into a cache, then runs it and removes it again.

Just to note that the check does not appear to follow modules installed in local files. I have a locally built version of @flowfuse/node-red-dashboard, so in package.json I see
"@flowfuse/node-red-dashboard": "file:../nodes/node-red-dashboard",

npm list axios shows

โ””โ”€โ”ฌ @flowfuse/node-red-dashboard@1.30.2 -> ./../nodes/node-red-dashboard
  โ”œโ”€โ”€ axios@1.13.5

but the script says that axios is not found in this projects lock file.

It does (partially) follow local file installs. On my dev instance, I have a local development version of uibuilder installed. Searching for "express", I get these results (NB: the package.json in my userDir folder has a name of node-red-userDir)

  *** FOUND: 3 installed instances of "express" ***

  Installed version : 5.2.1
  Location          : nested โ€” node_modules/@modelcontextprotocol/sdk/node_modules/express
  Depended on by    :
    โ€ข @modelcontextprotocol/sdk

  Installed version : 4.22.1
  Location          : top-level (hoisted)
  Depended on by    :
    โ€ข ../../node-red-contrib-uibuilder
    โ€ข @flowfuse/node-red-dashboard
    โ€ข express-rate-limit

  Installed version : 4.22.1
  Location          : nested โ€” node_modules/node-red-contrib-web-worldmap/node_modules/express
  Depended on by    :
    โ€ข node-red-contrib-web-worldmap

Which does indeed include the version in the local uibuilder install.

However, as you point out, if the top-level lock file doesn't include the searched for package AND it isn't used anywhere else, then it doesn't find it, as in this example searching for jsdom:

  Checking node-red-userdir ... not found

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Project : node-red-userdir
Rel path: .
Path    : D:\src\nr\data
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  (not found โ€” "jsdom" is not in this project's lock file)
npm ls jsdom
node-red-userdir@2.2.0 D:\src\nr\data
`-- node-red-contrib-uibuilder@7.6.0 -> .\..\..\node-red-contrib-uibuilder
  `-- jsdom@28.1.0

So there is an issue where it clearly isn't fully walking down the tree of package.json files whereas npm ls does.

I'll try to see if I can fix that. Thanks for pointing it out.

Already fixed and published as v1.1.0 :smiley:

Thank you for the fix.
My node-red package is in a docker container, and when I run npm-supply-chain-check I get this result

โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Supply-Chain Dependency Checker
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
Target  : node-red
Scope   : /usr/src/node-red
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Searching for npm project roots (directories with package.json + node_modules)...
Found 1 project root(s). Analysing lock files...

  Checking node-red-docker ... FOUND (1 instance)

โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Project : node-red-docker
Rel path: .
Path    : /usr/src/node-red
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  *** FOUND: 1 installed instance of "node-red" ***

  Installed version : 4.1.1
  Location          : top-level (hoisted)
  Direct dependency : yes
  Depended on by    :
    โ€ข (project root / direct dependency)


โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
SUMMARY
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
  Projects scanned      : 1
  Skipped (no lock file): 0
  "node-red" found in     : 1 project(s)

  *** Review the dependency details above for version risks.    ***
  *** Check the package's changelog and known CVEs immediately. ***
โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•

Yep, sorted.

Yes, that is correct, you searched for node-red and it found it.

(post deleted by author)

I won't be able to make it work with DinD setups because it adds a new set of threats and complexity that will make the security guards via filesystem way more fragile.