Aug 7, 2026·7 min read·136 visits
Legacy versions of crypto-js generate weak keys using Math.random() in a custom MWC generator, enabling attackers to systematically brute-force and drain cryptocurrency wallets.
A severe, twelve-year-old cryptographic weakness in crypto-js (versions < 4.0.0) generated pseudorandom numbers using a custom Multiply-With-Carry (MWC) algorithm seeded from the non-secure Math.random(). This reduces 128-bit and 256-bit key spaces to just 2^39 and 2^47 possibilities, allowing offline brute-force attacks.
The crypto-js library is a widely deployed JavaScript implementation of cryptographic standards, providing developers with hashing, cipher, and key derivation utilities. In versions preceding 4.0.0, the library exposed a critical vulnerability within its pseudorandom number generator (PRNG) implementation, specifically located in CryptoJS.lib.WordArray.random(). This component is commonly utilized by downstream applications to generate cryptographic keys, initialization vectors, and mnemonic seed phrases.\n\nThe underlying weakness stems from the implementation of a custom Multiply-With-Carry (MWC) algorithm seeded by the non-cryptographically secure function Math.random(). This design deviates from standard cryptographic engineering practices, which dictate the use of native, operating-system-level cryptographically secure PRNGs (CSPRNGs). Consequently, any cryptographic secret generated using these versions of the library suffers from a severe lack of entropy.\n\nThe vulnerability is cataloged as CVE-2026-71851 and carries a CVSS v3.1 base score of 9.0. The compromised entropy allows remote, unauthenticated attackers to systematically reconstruct generated secrets. This poses a threat to decentralized applications, cryptocurrency wallets, and authentication systems relying on historical installations of the library.
The root cause of CVE-2026-71851 is the implementation of a custom variation of George Marsaglia's Multiply-With-Carry (MWC) algorithm in src/core.js. This custom generator was introduced to synthesize random words for CryptoJS.lib.WordArray.random(). Rather than sourcing security-hardened entropy, the implementation initializes the generator state using the standard JavaScript Math.random() function.\n\nThe seed initialization relies on the expression Math.random() * 0x100000000. JavaScript performs bitwise operations on 32-bit signed integers, which causes any precision beyond 32 bits to be truncated. This mathematical constraint bounds the initial starting entropy of the seed state, m_w, to a maximum of 32 bits. The state is then updated deterministically inside a loop, meaning the generator does not integrate fresh, independent source entropy during subsequent iterations.\n\nFor each subsequent word generated, the only dynamic input is a single-bit sign conditional: Math.random() > 0.5 ? 1 : -1. Consequently, a 128-bit key (requiring four 32-bit words) receives 32 bits of initial seed entropy plus 8 bits of sign-choice entropy, culminating in approximately 40 bits of total entropy. For a 256-bit key, the generator yields roughly 48 bits of entropy, reducing the effective keyspace to 2^47 states, which is trivial to brute-force on modern hardware.
The original vulnerable random generation logic was implemented as follows in crypto-js prior to version 4.0.0:\n\njavascript\nrandom: function (nBytes) {\n var words = [];\n var r = (function (m_w) {\n var m_w = m_w;\n var m_z = 0x3ade68b1;\n var mask = 0xffffffff;\n return function () {\n m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;\n m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;\n var result = ((m_z << 0x10) + m_w) & mask;\n result /= 0x100000000;\n result += 0.5;\n return result * (Math.random() > .5 ? 1 : -1);\n }\n });\n for (var i = 0, rcache; i < nBytes; i += 4) {\n var _r = r((rcache || Math.random()) * 0x100000000);\n rcache = _r() * 0x3ade67b7;\n words.push((_r() * 0x100000000) | 0);\n }\n return new WordArray.init(words, nBytes);\n}\n\n\nAn intermediate patch attempted to secure this via a wrapper (secureRandom) but introduced precision loss and collisions. The wrapper converted high-entropy buffers to strings and parsed them back to floats, collapsing multiple distinct seeds into identical values (e.g., '0.1', '0.10', and '0.100' all evaluate to the float 0.1).\n\nThe robust patch in version 4.0.0 completely eliminated the custom generator in favor of platform-native cryptographic primitives. It routes entropy collection directly to crypto.randomBytes() in Node.js environments and window.crypto.getRandomValues() in browser environments. This preserves full 32-bit entropy per generated word.\n\nmermaid\ngraph LR\n Start["Math.random()"] -->|Truncation to 32-bit| Seed["m_w Seed (32 bits)"]\n Seed -->|Loop Iterations| Gen["MWC State Machine"]\n Gen -->|Sign Choices (+1 bit/word)| Out["Output WordArray"]\n Out -->|128-bit Key| Ent1["40 Bits Total Entropy"]\n Out -->|256-bit Key| Ent2["48 Bits Total Entropy"]\n
Exploitation of CVE-2026-71851 does not require an active, interactive network payload. Instead, attackers execute passive, offline brute-force attacks against target public keys or addresses harvested from public blockchain ledgers. The primary prerequisite is that the target account was generated using a vulnerable version of crypto-js (typically bundled in unmaintained hybrid mobile apps or browser-based wallets).\n\nThe attack methodology involves reconstructing the custom MWC state generator. Threat actors seed the simulated generator with values starting from 0 to 2^32 - 1. For each seed, the actor simulates the sign-conditional choices, producing candidates for the 12-word or 24-word BIP39 mnemonic phrases.\n\nOnce the candidate mnemonic phrases are generated, they are programmatically derived into cryptographic public addresses using standard derivation paths (such as BIP44 for Ethereum or Bitcoin). If a derived address matches an active address on the blockchain, the corresponding private key is exposed, enabling the attacker to sign transactions and transfer assets. The entire keyspace can be exhaustively scanned in a highly parallelized manner using graphics processing units (GPUs).
The impact of this cryptographic failure is severe, leading to unauthorized asset transfer and full compromise of secret key material. In cryptocurrency contexts, the generation of low-entropy private keys renders wallet recovery phrases guessable. Since the public ledger reveals all active addresses, attackers can verify candidate keys offline without triggering any network security controls or rate-limiting mechanisms.\n\nFor non-blockchain applications, the vulnerability compromises session tokens, password reset tokens, and API credentials generated via WordArray.random(). If an application uses these keys for HMAC signatures, an attacker can forge signatures and bypass authentication entirely. Because the underlying entropy is bound to a maximum of 48 bits, traditional high-strength algorithms (such as AES-256) offer no real security, as the key space is restricted to a fraction of its intended strength.\n\nThe CVSS v3.1 score of 9.0 reflects the critical nature of the compromise. Although the attack complexity is classified as High due to the requirement of offline brute-forcing and blockchain state verification, the impact on confidentiality, integrity, and availability is maximum (High). There is documented evidence of active exploitation of this vulnerability in the wild under the security campaign name 'Ill Bloom'.
Remediation of CVE-2026-71851 requires a multi-phase approach encompassing software upgrades, code audits, and secret rotation. The primary action is to upgrade crypto-js to version 4.0.0 or higher. Developers must audit their transitive dependency trees using package manager tools like npm ls crypto-js or yarn why crypto-js to ensure older version ranges (such as 3.x) are completely purged from application bundles.\n\nIf upgrading the package is not immediately viable, developers must override the default random generator. This can be achieved by writing a secure polyfill that overrides CryptoJS.lib.WordArray.random with a custom function utilizing window.crypto.getRandomValues or Node.js's native crypto.randomBytes. A sample remediation snippet for browser environments is detailed below:\n\njavascript\nCryptoJS.lib.WordArray.random = function (nBytes) {\n var words = [];\n var r = new Uint32Array(Math.ceil(nBytes / 4));\n window.crypto.getRandomValues(r);\n for (var i = 0; i < nBytes; i += 4) {\n words.push(r[i / 4]);\n }\n return new CryptoJS.lib.WordArray.init(words, nBytes);\n};\n\n\nImportantly, software patches do not retroactively secure keys, secrets, or mnemonic phrases that were generated using the vulnerable code. Any cryptographic asset, API token, or cryptocurrency seed phrase generated under crypto-js versions prior to 4.0.0 must be treated as permanently compromised. Users and administrators must generate new secrets using a cryptographically secure generator and migrate all associated assets and configurations immediately.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
crypto-js brix | >= 3.1.2-4, < 4.0.0 | 4.0.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-338 |
| Attack Vector | Network |
| CVSS v3.1 Score | 9.0 (Critical) |
| Exploit Status | Active In-The-Wild |
| Primary Impact | Private Key Compromise and Asset Theft |
| Component | CryptoJS.lib.WordArray.random() |
The product uses a pseudorandom number generator (PRNG) in a security context, but the PRNG's algorithm is not cryptographically strong.
A security feature bypass vulnerability in the Falco k8saudit plugin (and its cloud-specific variants) allowed privileged workloads to run undetected. This bypass occurred because the plugin's default extraction logic and rules only evaluated standard containers, completely omitting initContainers and ephemeralContainers.
nginx-ignition is a web-based user interface for managing the Nginx web server. In versions 2.33.0 through 2.35.0, the application is vulnerable to an improper authentication flaw (CWE-287) in its Multi-Factor Authentication (MFA) implementation. The stateless validation of Time-Based One-Time Passwords (TOTP) allows an attacker to reuse a captured, active verification code multiple times within the standard 30-second validity window, successfully bypassing secondary authentication checks if primary credentials are known.
A vulnerability exists in the i18n middleware of nginx-ignition, enabling CPU amplification attacks. By transmitting a crafted Accept-Language header containing malformed tags separated by underscores, an unauthenticated remote attacker can bypass the length-guard threshold of the underlying Go parsing library. Normalization of underscores to hyphens occurs after the initial validation checks, forcing the parser into expensive quadratic-time loops that consume 100% of available CPU resources. This leads to a complete denial of service for the administrative API and potentially degrades the availability of the hosting system. This vulnerability has been resolved in version 2.40.1.
Nginx Ignition prior to version 2.41.1 contains a Time-of-Check to Time-of-Use (TOCTOU) race condition in its unauthenticated onboarding API endpoint. This flaw allows remote, unauthenticated attackers to register an administrative account by sending concurrent HTTP requests during the initial system configuration phase, bypassing the check meant to restrict onboarding to a single initial administrator.
A logic error in Hatchet's OAuth state validation mechanism allows unauthenticated remote attackers to bypass state parameter verification. By submitting an empty state parameter, attackers can exploit an equality collision with cleared session keys, facilitating Login Cross-Site Request Forgery (Login CSRF) or Session Fixation.
A high-severity access control vulnerability in ToolHive CLI before v0.30.1 and ToolHive Studio before v0.38.0 allows local containerized MCP servers to bypass network isolation. This enables malicious workloads to establish TCP/IP connections to administrative and control plane endpoints exposed on the host loopback interface.