Security Vulnerabilities by Category: Which Package Types Are Riskiest?
·PkgPulse Team
TL;DR
Input parsing, HTTP handling, and cryptography packages have the highest vulnerability density in the npm ecosystem. But frequency of CVEs isn't the same as severity — many high-CVE categories get patched quickly, while some rarely-updated categories silently accumulate vulnerabilities. The worst combination: old input-parsing packages that nobody has audited in years, sitting in your dependency tree processing untrusted user data.
Key Takeaways
- Input parsing (XML, CSV, YAML, URL) — highest CVE density, especially ReDoS and prototype pollution
- Authentication packages — critical severity when vulnerable (credentials, tokens)
- Cryptography wrappers — silent failure modes are the most dangerous
- Build tools — mostly dev vulnerabilities (less critical, still patch them)
- The real risk: time between CVE disclosure and your patch adoption
Vulnerability Distribution by Category (npm, 2024-2026)
CVE count by package category (approximate, based on npm advisories):
Input/Parsing: 38% of CVEs
├── Regular expressions (ReDoS): 45% of parsing CVEs
├── Prototype pollution: 30%
├── Buffer overflow: 15%
└── Path traversal: 10%
HTTP/Networking: 22% of CVEs
├── SSRF (Server-Side Request Forgery): 35%
├── Request smuggling: 20%
├── Open redirect: 25%
└── Information disclosure: 20%
Authentication/Auth: 18% of CVEs
├── Token validation bypass: 40%
├── Session fixation: 20%
├── Timing attacks: 25%
└── Weak defaults: 15%
Cryptography: 12% of CVEs
├── Weak algorithm defaults: 50%
├── IV reuse / predictable random: 30%
└── Key exposure: 20%
Other categories: 10%
├── Build tools (dev-only): mostly prototype pollution
├── CLI tools: command injection
└── Various utilities: mixed
Category 1: Input Parsing (Highest Risk)
The ReDoS Threat
// ReDoS: Regular Expression Denial of Service
// Attacker provides crafted input that causes exponential regex backtracking
// Result: CPU spike, server hangs, DoS
// Packages historically affected by ReDoS:
// - semver < 7.5.2 (patched)
// - minimatch < 3.0.5 (patched)
// - glob-parent < 5.1.2 (patched)
// - validator.js (multiple advisories)
// - moment.js (parsing specific formats)
// Defense:
// ✅ Use package overrides to force patched versions
// ✅ Set timeouts on regex operations if building custom parsers
// ✅ Validate/sanitize input length before parsing
// ✅ Use a ReDoS scanner: npm install -D safe-regex
import safeRegex from 'safe-regex';
safeRegex(/^(a+)+$/); // returns false: vulnerable to catastrophic backtracking
Prototype Pollution
// Prototype pollution: attacker manipulates Object.prototype
// via deep merge operations on user-supplied data
// Affects: every object in the application silently
// Historically affected packages:
// - lodash < 4.17.21 (patched in 4.17.21)
// - minimist < 1.2.6 (patched)
// - deep-merge (various old versions)
// - jquery (via $.extend())
// Defense:
// Use Object.create(null) for user data containers
const userInput = Object.create(null); // No prototype chain
// Or freeze Object.prototype (defensive but can break libraries):
Object.freeze(Object.prototype);
// Use safe-merge utilities:
import { merge } from 'lodash'; // v4.17.21+ is safe
// or:
const safe = structuredClone(userInput); // Deep clone breaks prototype chain
Category 2: Authentication Packages (Highest Severity)
// jsonwebtoken — historically high-profile vulnerabilities
// CVE-2022-23529: remote code execution via algorithms["HS256"]
// CVE-2022-23540: algorithm confusion attack
// Patched in: jsonwebtoken@9.0.0
// Best practice for JWT in 2026:
import { SignJWT, jwtVerify } from 'jose'; // Modern, audited alternative
// jose: actively maintained, WebCrypto API based, no legacy baggage
// Verify with explicit algorithm:
const { payload } = await jwtVerify(token, secret, {
algorithms: ['HS256'], // Always specify; never allow 'none'
});
// bcrypt / password hashing vulnerabilities:
// bcryptjs: pure JS, some historical timing issues
// argon2: better algorithm (memory-hard), no historical CVEs in Node binding
// scrypt: built into Node.js crypto, use for new projects
import { scrypt, randomBytes, timingSafeEqual } from 'crypto';
// Use built-in Node.js crypto for password hashing when possible
Category 3: HTTP Client/Server Packages
// SSRF: Server-Side Request Forgery
// Your app makes HTTP requests based on user-controlled input
// Attacker points to internal services (localhost, AWS metadata endpoint)
// Vulnerable pattern:
app.get('/proxy', async (req, res) => {
const url = req.query.url; // ❌ User controls URL
const data = await fetch(url); // ❌ Can hit internal services
res.json(data);
});
// Defense:
import { URL } from 'url';
function isSafeUrl(urlStr: string): boolean {
try {
const url = new URL(urlStr);
// Block private/internal addresses
const blocked = ['localhost', '127.0.0.1', '::1', '169.254.169.254'];
if (blocked.some(b => url.hostname === b || url.hostname.endsWith('.internal'))) {
return false;
}
// Only allow HTTP/HTTPS
if (!['http:', 'https:'].includes(url.protocol)) return false;
return true;
} catch {
return false;
}
}
// Open redirect:
// Never redirect to user-controlled URLs without validation
// ❌ res.redirect(req.query.returnUrl)
// ✅ Validate against allowlist of known safe paths
Category 4: Cryptography Packages
// Weak defaults: many packages used weak algorithms historically
// DES, MD5, SHA1 → all broken for security purposes
// Common issues still found in codebases:
// ❌ MD5 for anything security-related
import crypto from 'crypto';
const hash = crypto.createHash('md5').update(password).digest('hex');
// MD5 is broken. Do not use for passwords or security checks.
// ✅ For passwords: argon2 or scrypt (built-in)
// ✅ For content hashes/ETags: SHA256 is fine
const hash = crypto.createHash('sha256').update(content).digest('hex');
// ❌ Predictable random number generation
const token = Math.random().toString(36); // NOT cryptographically secure
// ✅ Cryptographically secure random:
const token = crypto.randomBytes(32).toString('hex'); // Built-in
const id = crypto.randomUUID(); // UUID v4, cryptographically secure
// ❌ Reusing initialization vectors (IV) in encryption
// Always generate a fresh random IV for each encryption:
const iv = crypto.randomBytes(16); // Fresh IV every time
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);
Which Packages Get Patched Fastest vs Slowest
Time to patch after CVE disclosure (average, by package category):
< 7 days:
→ Build tools (webpack, vite, rollup)
→ Test frameworks (jest, vitest)
→ Major framework packages (react, vue, angular)
→ Well-funded corporate packages (Next.js, Fastify)
7-30 days:
→ Authentication packages (high priority due to impact)
→ Active utility libraries (lodash, zod)
→ Well-maintained HTTP clients
30-90 days:
→ Mid-tier utility packages
→ Single-maintainer packages with active developers
→ Packages in "maintenance mode" (express: patches still come)
> 90 days or never:
→ Abandoned packages (create-react-app, request, bower)
→ Deep transitive deps that nobody monitors
→ Packages with inactive maintainers
PkgPulse health score factors in:
- Average historical patch time for the maintainer
- Currently open CVEs
- Time since last security advisory
Your Vulnerability Exposure Profile
# Assess your project's security posture:
# 1. Run npm audit
npm audit
# Focus on HIGH and CRITICAL
# LOW/MODERATE: informational, address when convenient
# 2. See the dependency tree for a vulnerability
npm audit --json | jq '.vulnerabilities.semver.nodes'
# Shows: which of YOUR direct deps brings in the vulnerable package
# 3. Check for critical attack surfaces
# High risk: packages handling user input + network I/O
npm ls --all | grep -E "(xml|yaml|csv|html-parser|url-parse|qs)"
# These are high-value targets: input + potential injection
# 4. Look for single-maintainer packages in your tree
npm ls --all 2>/dev/null | head -100
# For each, check: npmjs.com/package/{name} → maintainers count
# 5. Socket security scan (behavioral, not just CVE)
npx @socket/cli report create # Analyzes your package.json
Risk Reduction Checklist
High impact, quick wins:
[ ] Run npm audit — fix all HIGH and CRITICAL findings
[ ] Force override vulnerable transitive deps via package.json overrides
[ ] Replace deprecated packages (request, node-fetch v2, create-react-app)
[ ] Enable Dependabot or Renovate for automated security PRs
Medium effort:
[ ] Audit all packages that parse user input (XML, YAML, CSV, HTML)
[ ] Review authentication packages — are they on latest versions?
[ ] Check cryptography code — any MD5/SHA1/DES usage?
[ ] Add Socket.dev scanning to CI
Ongoing:
[ ] Subscribe to npm security advisories (security.snyk.io)
[ ] Review `npm audit` in CI weekly (via cron workflow)
[ ] Monitor PkgPulse health scores for packages you depend on
[ ] Check single-maintainer packages for activity once per quarter
Monitor security scores and vulnerability data for npm packages at PkgPulse.
See the live comparison
View npm vs. pnpm on PkgPulse →