· 5 min read

The fs@0.0.1-security Package Isn't What You Think

Kief Studio
The fs@0.0.1-security Package Isn't What You Think

Here's the full blog post:


The fs@0.0.1-security Package Isn't What You Think

Run npm ls fs in any non-trivial Node.js project. Go ahead, I'll wait.

If you see fs@0.0.1-security in that tree, your security scanner is probably losing its mind right now. AWS Inspector calls it CVSS 9.8 -- critical malware. Your SIEM is lighting up. Someone on your team just opened a Jira ticket with "URGENT" in the title.

Here's the thing: that package is empty. Literally empty. npm's security team put it there on purpose. And the fact that your tooling can't tell the difference between a placeholder and an actual supply chain attack is a bigger problem than the placeholder itself.

What fs@0.0.1-security Actually Is

Node.js ships with a built-in fs module. You've used it a thousand times:

const fs = require('fs');
fs.readFileSync('/etc/passwd'); // works fine, no npm install needed

At some point, someone published a malicious fs package to npm that impersonated the built-in module. Classic typosquatting, except it wasn't even a typo -- it was the exact name. npm's security team seized the package name and published 0.0.1-security as a placeholder. The version string is the message: "we took this over, nothing to see here."

The package has no code. No index.js. No exports. It's a package.json with a description that says "This package name is not currently in use."

It has 351 million total downloads. About 1.25 million per week.

Why It's Still in Your Lockfile

Someone, somewhere in your dependency tree, listed fs as a dependency in their package.json. They didn't need to -- require('fs') resolves to the built-in module regardless -- but they did, and npm dutifully installed the placeholder.

You can find it:

# Check if fs is in your dependency tree
npm ls fs

# Example output:
# my-app@1.0.0
# +-- some-legacy-lib@2.3.1
# |   +-- fs@0.0.1-security
# +-- another-package@4.1.0
#     +-- old-util@1.0.3
#         +-- fs@0.0.1-security

It's transitive. You didn't install it. Some package you depend on did, or some package they depend on did. The average npm project pulls in 79 transitive dependencies. This stuff nests deep.

The Scanner Fatigue Problem

Here's where it gets bad. The OSSF Malicious Packages Database includes an entry for fs -- MAL-2025-21003. Makes sense: the original package was malicious. But scanners don't read context. They see the package name, they see the advisory, they flag it as critical.

AWS Inspector assigns it CVSS 9.8. That's the same severity as a remote code execution with no authentication required. For an empty package.

This isn't hypothetical. LiteLLM's dashboard had fs@0.0.1-security in its package-lock.json. Inspector flagged it. Engineers investigated. Hours burned on a false positive.

The irony is brutal: while teams were chasing the fs phantom, LiteLLM was actually compromised -- on PyPI, not npm. The TeamPCP campaign injected malware into LiteLLM versions 1.82.7 through 1.82.8, stealing SSH keys, cloud credentials, Kubernetes configs, and npm auth tokens. The real attack came through a completely different vector that nobody was looking at because they were busy investigating the wrong alert.

This is textbook alert fatigue. When your scanner cries wolf on an empty placeholder, teams learn to dismiss critical findings. And then the actual wolf shows up on a different channel entirely.

What's Actually Happening in npm Right Now

The fs placeholder is noise. The signal is much worse.

In 2025, 454,648 malicious packages were published to npm. That's not a typo. Over 99% of all open-source malware now targets the npm ecosystem. The IndonesianFoods campaign alone generated over 100,000 malicious packages by publishing one every seven seconds.

North Korean state actors -- Lazarus Group and Sapphire Sleet -- published over 800 malicious npm packages in 2025. In March 2026, Sapphire Sleet compromised Axios, which has 70+ million weekly downloads, deploying a remote access trojan. Microsoft published a formal advisory.

The September 2025 chalk/debug compromise exposed 2.8 billion weekly downloads to a cryptocurrency clipper. The attacker phished a maintainer by impersonating npm support, took over 18 packages, and injected malware. Total financial haul: less than five cents. But the industry spent thousands of collective hours on incident response.

Dependency confusion attacks are now targeting specific companies by name. In April 2026, SafeDep caught @genoma-ui/components -- a package name chosen to match Brazilian identity company Unico's internal design system. Attackers are researching your internal package names and registering them on the public registry.

Self-replicating worms (the Shai-Hulud family) have made npm the first ecosystem with autonomous supply chain malware that spreads without attacker intervention.

This is the landscape. And your scanner is spending its budget on fs@0.0.1-security.

What to Actually Do About It

First, check what's in your lockfile. Not what your scanner says is there -- what's actually there:

# See every package in your tree with its resolved version
npm ls --all --depth=Infinity 2>/dev/null | head -50

# Check specifically for known-placeholder packages
npm ls fs 2>/dev/null
npm ls events 2>/dev/null
npm ls util 2>/dev/null
npm ls path 2>/dev/null

If fs@0.0.1-security shows up, trace it back to the parent that declared it:

# Find which package requires fs
npm explain fs

If the parent package is something you control, remove fs from its package.json dependencies. If it's a third-party package, open an issue or a PR. It's a one-line fix and maintainers generally accept it.

Second, pin your dependencies. Not just direct deps -- use a lockfile and actually commit it:

# Ensure your lockfile is committed and CI uses it
npm ci  # NOT npm install -- ci respects the lockfile exactly

Third, scan for what matters. The kief.dev Security Headers tool catches misconfigured HTTP headers that are often the real entry point for attacks. And if you want to check your lockfiles against actual malicious package advisories -- not placeholder false positives -- Vekt scans 22 lockfile formats across 12 ecosystems against OSV.dev's database, which includes both CVEs and MAL-* malicious package entries.

# Quick scan of your project's lockfiles
vekt scan .

# Example output:
# Scanning package-lock.json...
# Found 847 packages across 1 lockfile
#
# [MAL] axios@1.7.8-rc.1  MAL-2026-3391  Sapphire Sleet RAT
# [CVE] lodash@4.17.20    CVE-2021-23337  Command Injection
#
# 2 findings (1 malicious, 1 vulnerability)
# 845 packages clean

The difference: Vekt reports fs@0.0.1-security as what it is -- a placeholder -- not as critical malware. Because reading the advisory metadata before assigning a CVSS score isn't that hard.

Fourth, enable two-factor authentication on your npm account. Right now. The chalk/debug compromise started with a phished maintainer. CISA issued a formal advisory after the September 2025 attack urging phishing-resistant MFA for all package maintainers.

npm profile enable-2fa auth-and-writes

The Actual Takeaway

The fs@0.0.1-security package is doing exactly what it was designed to do: sitting there, being nothing, preventing anyone else from claiming the name. That's good.

The problem is that security tooling has become a fire hose of alerts with no filter for context. A placeholder published by npm's own security team gets the same CVSS 9.8 as an actual RAT deployed by North Korean state actors. When everything is critical, nothing is.

Your lockfile is an attack surface. Treat it like one. But treat it with the same engineering discipline you'd apply to any other system: understand what's in it, know which alerts are signal vs. noise, and spend your limited security hours on the threats that are actually there.

The scary part about npm supply chain security isn't the empty packages your scanner is yelling about. It's the 454,648 malicious packages that went up last year, the nation-state actors publishing under innocuous names, and the dependency confusion attacks targeting your company specifically. Focus there.


meta_title: "fs@0.0.1-security: The npm Package That Breaks Scanners"
meta_description: "npm's fs placeholder has 351M downloads and triggers CVSS 9.8 false positives. Here's what it actually is and what to worry about instead."
tags: ["npm", "supply-chain-security", "javascript", "dependency-management", "appsec"]