You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a string passphrase is passed, crypto-js internally routes through PasswordBasedCipher → OpenSSLKdf → EvpKDF, which derives the AES key using:
Hash: MD5 — cryptographically broken since 2004
Iterations: 1 — provides zero resistance against brute force
Cipher mode: CBC — no authentication (vulnerable to padding oracle attacks)
The README does not mention any of these implementation details. Developers copying the example get encryption where a GPU can test billions of candidate passphrases per second (single MD5 hash), and the ciphertext has no integrity protection.
What's happening internally
Tracing the code path in src/cipher-core.js and src/evpkdf.js:
The v4.2.0 release notes say: "Change default hash algorithm and iteration's for PBKDF2 to prevent weak security by using the default configuration." The team recognized weak KDF defaults as a security issue — but only fixed the standalone PBKDF2 module. The AES passphrase encryption path still uses EvpKDF with MD5/1-iteration.
Similarly, v4.0.0 replaced Math.random() with native crypto for random number generation. The library's RNG is now cryptographically secure — but the key derivation that feeds into AES encryption is a single MD5 hash, making the improved RNG irrelevant for passphrase-based encryption.
CWEs
CWE-328: Use of Weak Hash (MD5 for key derivation)
CWE-916: Use of Password Hash With Insufficient Computational Effort (1 iteration)
CWE-354: Improper Validation of Integrity Check Value (CBC without authentication)
Suggested documentation fix
Add a security note to the AES examples:
⚠️ Security Note: When passing a string passphrase, crypto-js derives the AES key using OpenSSL's EVP_BytesToKey with MD5 and 1 iteration. This provides minimal resistance against brute force. For production use, either:
Derive keys explicitly using CryptoJS.PBKDF2() with SHA-256 and ≥600,000 iterations, then pass the derived WordArray as the key
Use the native crypto module with crypto.scrypt() or crypto.pbkdf2() for key derivation, and crypto.createCipheriv() with aes-256-gcm for authenticated encryption
Context
This issue is part of a broader pattern documented across npm libraries: libraries with secure code improvements that still teach insecure patterns in their documentation. Analysis: The Documentation Attack Surface
Summary
The README's AES encryption examples use passphrase-based encryption:
When a string passphrase is passed, crypto-js internally routes through
PasswordBasedCipher→OpenSSLKdf→EvpKDF, which derives the AES key using:The README does not mention any of these implementation details. Developers copying the example get encryption where a GPU can test billions of candidate passphrases per second (single MD5 hash), and the ciphertext has no integrity protection.
What's happening internally
Tracing the code path in
src/cipher-core.jsandsrc/evpkdf.js:typeof key == 'string'→ selectsPasswordBasedCipherPasswordBasedCipher.encrypt()callscfg.kdf.execute(password, cipher.keySize, cipher.ivSize, cfg.salt, cfg.hasher)OpenSSLKdf.execute()usesEvpKDFwith default config:{ hasher: MD5, iterations: 1 }{ mode: CBC, padding: Pkcs7 }— no authenticationWhy this matters
The irony
The v4.2.0 release notes say: "Change default hash algorithm and iteration's for PBKDF2 to prevent weak security by using the default configuration." The team recognized weak KDF defaults as a security issue — but only fixed the standalone PBKDF2 module. The AES passphrase encryption path still uses EvpKDF with MD5/1-iteration.
Similarly, v4.0.0 replaced
Math.random()with native crypto for random number generation. The library's RNG is now cryptographically secure — but the key derivation that feeds into AES encryption is a single MD5 hash, making the improved RNG irrelevant for passphrase-based encryption.CWEs
Suggested documentation fix
Add a security note to the AES examples:
Context
This issue is part of a broader pattern documented across npm libraries: libraries with secure code improvements that still teach insecure patterns in their documentation. Analysis: The Documentation Attack Surface
Previously filed: