Detects usage of weak hash algorithms (MD5, MD4, SHA-1, RIPEMD) in Node.js crypto operations. This rule is part of eslint-plugin-node-security and provides LLM-optimized error messages with fix suggestions.
🚨 Security rule | 💡 Provides suggestions | ⚠️ Set to error in recommended
Vulnerability: MD5, MD4, SHA-1, and RIPEMD are cryptographically broken hash algorithms. They are vulnerable to collision attacks which allow attackers to create different messages with the same hash.
Risk: Using weak hash algorithms for security-sensitive operations (password hashing, digital signatures, file integrity) can allow attackers to forge signatures, create colliding files, or perform preimage attacks.
These examples name a security use (password, signature, token,
integrity), which is what makes them fire under the default options. The
block previously used neutral names like hash and sha1Hash and therefore
reported nothing — see Unclassified hashes below
for why, and set reportUnclassifiedHashes: true to also flag weak hashes
whose name gives no purpose. Names listed in nonCryptographicNames stay
exempt either way.
A digest compared against such a value is a security use too — the
comparison is the check a collision defeats. Besides the securityUseNames,
a comparison against a value named mac or digest counts:
if (signature === crypto.createHash('md5').update(body).digest('hex')) accept();
For a bare helper call (sha1(data)), the sha256(...) suggestion is offered
only when a sha256 is callable there. A file that defines or imports its own
sha1 and has no sha256 gets the report without a suggestion.
Why: This is the largest false-negative class, and it is a deliberate
trade rather than an analysis limit. By default (reportUnclassifiedHashes: false) a weak hash is reported only when a securityUseNames word is visible
at the site. A digest whose surrounding identifiers name no security use is
not reported, however the value is then used:
// ❌ NOT DETECTED - no securityUseNames word at the siteconst sha1 = (buf: Buffer) => createHash('sha1').update(buf).digest('hex');const shasum = sha1(archive);if (published !== shasum) throw new Error('tarball integrity mismatch');
This is a real supply-chain integrity check on a downloaded archive, and it is
silent. Renaming shasum to integrity makes the identical code report
CRITICAL, because integrity IS in securityUseNames — so the discriminator
is the vocabulary that happens to appear, not the security semantics.
Mitigation: set reportUnclassifiedHashes: true, or name the binding after
what it protects so the classifier can see it.
SHA-1 is genuinely used here, but the algorithm is not the author's choice and
breaking its collision resistance buys nothing — the value indexes a script the
server already holds. The same shape covers HTTP ETags, content-addressed
caches, and cache busting.
A hash assigned to a name in nonCryptographicNames is not reported. The
test is where the value lands, not which API produced it: the rule walks out
through the .update(...).digest(...) receiver chain and reads the assignment
target. A hash that is returned, passed as an argument, compared, or stored
under a computed key is not exempted by this rule — so renaming a variable
to sha cannot silence a hash the classifier had already decided to report.
That is a statement about the nonCryptographicNames exemption only, and it is
not a promise that such a hash reports. Under the default
reportUnclassifiedHashes: false, a digest with no securityUseNames word at
the site is never classified as a security control in the first place, so there
is nothing for the exemption to override. See
Unclassified hashes.
Set nonCryptographicNames: [] to switch the exemption off.