CVE-2025-6545 – pbkdf2
Package
Manager: npm
Name: pbkdf2
Vulnerable Version: >=3.0.10 <3.1.3
Severity
Level: Critical
CVSS v3.1: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:N/E:U/RL:O/RC:C
CVSS v4.0: CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:H/VA:N/SC:H/SI:H/SA:H
EPSS: 0.0012 pctl0.31675
Details
pbkdf2 returns predictable uninitialized/zero-filled memory for non-normalized or unimplemented algos ### Summary This affects both: 1. Unsupported algos (e.g. `sha3-256` / `sha3-512` / `sha512-256`) 2. Supported but non-normalized algos (e.g. `Sha256` / `Sha512` / `SHA1` / `sha-1` / `sha-256` / `sha-512`) All of those work correctly in Node.js, but this polyfill silently returns highly predictable ouput Under Node.js (only with `pbkdf2/browser` import, unlikely) / Bun (`pbkdf2` top-level import is affected), the memory is not zero-filled but is uninitialized, as `Buffer.allocUnsafe` is used Under browsers, it just returns zero-filled buffers (Which is also critical, those are completely unacceptable as kdf output and ruin security) ### Were you affected? The full list of arguments that were **not** affected were literal: * `'md5'` * `'sha1'` * `'sha224'` * `'sha256'` * `'sha384'` * `'sha512'` * `'rmd160'` * `'ripemd160'` Any other arguments, e.g. representation variations of the above ones like `'SHA-1'`/`'sha-256'`/`'SHA512'` or different algos like `'sha3-512'`/`'blake2b512'`, while supported on Node.js `crypto` module, returned predictable output on `pbkdf2` (or `crypto` browser/bundlers polyfill) --- Beware of packages re-exporting this under a different signature, like (abstract): ```js const crypto = require('crypto') module.exports.deriveKey = (algo, pass, salt) => crypto.pbkdf2Sync(pass, salt, 2048, 64, algo) ``` In this case, the resulting `deriveKey` method is also affected (to the same extent / conditions as listed here). ### Environments This affects `require('crypto')` in polyfilled mode (e.g. from `crypto-browserify`, `node-libs-browser`, `vite-plugin-node-polyfills`, `node-stdlib-browser`, etc. -- basically everything that bundles/polfyills `crypto` * In bundled code (e.g. Webpack / Vite / whatever), this affects `require('crypto')` and `require('pbkdf2')` * On Node.js, this does not affect `require('pbkdf2')` (or `require('crypto')` obviously), but affects `require('pbkdf2/browser')` * On Bun, this _does_ affect `require('pbkdf2')` _and_ `require('pbkdf2/browser')` (and returns uninitialized memory, often zeros / sparse flipped bytes) ### PoC ```js const node = require('crypto') const polyfill = require('pbkdf2/browser') const algos = [ 'sha3-512', 'sha3-256', 'SHA3-384', 'Sha256', 'Sha512', 'sha512-256', 'SHA1', 'sha-1', 'blake2b512', 'RMD160', 'RIPEMD-160', 'ripemd-160', ] for (const algo of algos) { for (const { pbkdf2Sync } of [node, polyfill]) { const key = pbkdf2Sync('secret', 'salt', 100000, 64, algo) console.log(`${algo}: ${key.toString('hex')}`); } } ``` Output (odd lines are Node.js, even is `pbkdf2` module / polyfill): ``` sha3-512: de00370414a3251d6d620dc8f7c371644e5d7f365ab23b116298a23fa4077b39deab802dd61714847a5c7e9981704ffe009aee5bb40f6f0103fc60f3d4cedfb0 sha3-512: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 sha3-256: 76bf06909b91e4c968700078ee36af92019d0839ab1fea2f345c6c8685074ca0179302633fbd84d22cff4f8744952b2d07edbfc9658e95d30fb4e93ee067c7c9 sha3-256: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 SHA3-384: 2b2b41b73f9b7bcd023f709ea84ba3c29a88edc311b737856ba9e74a2d9a928f233eb8cb404a9ba93c276edf6380c692140024a0bc12b75bfa38626207915e01 SHA3-384: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Sha256: 3fa094211c0cf2ed1d332ab43adc69aab469f0e0f2cae6345c81bb874eef3f9eb2c629052ec272ca49c2ee95b33e7ba6377b2317cd0dacce92c4748d3c7a45f0 Sha256: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 Sha512: 3745e482c6e0ade35da10139e797157f4a5da669dad7d5da88ef87e47471cc47ed941c7ad618e827304f083f8707f12b7cfdd5f489b782f10cc269e3c08d59ae Sha512: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 sha512-256: e423f61987413121418715d0ebf64cb646042ae9a09fe4fd2c764a4f186ba28cf70823fdc2b03dda67a0d977c6f0a0612e5ed74a11e6f32b033cb658fa9f270d sha512-256: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 SHA1: 0e24bc5a548b236e3eb3b22317ef805664a88747c725cd35bfb0db0e4ae5539e3ed5cd5ba8c0ac018deb6518059788c8fffbe624f614fbbe62ba6a6e174e4a72 SHA1: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 sha-1: 0e24bc5a548b236e3eb3b22317ef805664a88747c725cd35bfb0db0e4ae5539e3ed5cd5ba8c0ac018deb6518059788c8fffbe624f614fbbe62ba6a6e174e4a72 sha-1: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 blake2b512: d3d661100c5ffb79bdf3b5c77d1698e621414cba40e2348bd3f1b10fbd2fe97bff4dc7d76474955bfefa61179f2a37e9dddedced0e7e79ef9d8c678080d45926 blake2b512: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 RMD160: ec65dbad1485616cf0426725d64e009ad3e1633543746ccb56b7f06eb7ce51d0249aaef27c879f32911a7c0accdc83389c2948ddec439114f6165366f9b4cca2 RMD160: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 RIPEMD-160: ec65dbad1485616cf0426725d64e009ad3e1633543746ccb56b7f06eb7ce51d0249aaef27c879f32911a7c0accdc83389c2948ddec439114f6165366f9b4cca2 RIPEMD-160: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ripemd-160: ec65dbad1485616cf0426725d64e009ad3e1633543746ccb56b7f06eb7ce51d0249aaef27c879f32911a7c0accdc83389c2948ddec439114f6165366f9b4cca2 ripemd-160: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ``` #### Uninitialized memory ```js const { pbkdf2Sync } = require('pbkdf2/browser') // or just 'pbkdf2' on Bun will do this too let prev for (let i = 0; i < 100000; i++) { const key = pbkdf2Sync('secret', 'salt', 100000, 64, 'sha3-256') const hex = key.toString('hex') if (hex !== prev) console.log(hex); prev = hex } ``` ### Affected versions Seems to be since https://github.com/browserify/pbkdf2/commit/9699045c37a07f8319cfb8d44e2ff4252d7a7078 ### Impact This is critical, browserifying code might silently generate zero-filled keys instead of proper ones, for code that was working on Node.js or in test environment Just updating to a fixed version is not enough: if anyone was using `pbkdf2` lib (e.g. via `crypto-browserify` or directly) on algos not from the literal string list (see "were you affected"), recheck where those keys went / how they were used, and take action accordingly ### Note Most likely, you receive this either through a subdep using `pbkdf2` module directly (and then it is used), or through `crypto-browserify` (and the usage depends on whether you or any of your subdeps were calling `pbkdf2/pbkdf2Sync` methods from Node.js crypto inside your bundle) When targeting non-Node.js, prever avoiding Node.js crypto polyfill at all, and use `crypto.subtle` and/or modern/audited cryptography primitives instead
Metadata
Created: 2025-06-23T22:41:50Z
Modified: 2025-06-27T23:38:36Z
Source: https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/06/GHSA-h7cp-r72f-jxh6/GHSA-h7cp-r72f-jxh6.json
CWE IDs: ["CWE-20"]
Alternative ID: GHSA-h7cp-r72f-jxh6
Finding: F184
Auto approve: 1