
Technical Card Miggo Security Research Labs / Miggo Vulnerability Database
CVE-2026-71851 describes a cryptographic vulnerability involving insufficient entropy in CryptoJS.lib.WordArray.random() a packet crypto-js. In vulnerable releases, the generator relied on a user-defined variation of Multiply-With-Carry (MWC) initialized with Math.random(), rather than a cryptographically strong random source (CSPRNG). Therefore, nominal queries of 128 and 256 bits yield effective spaces of order 2^39 and 2^47; this transforms the problem from a cryptographically strong search to a feasible offline enumeration.
The “weak entropy → BIP39 mnemonic → seed → HD keys → controlled addresses” path is particularly dangerous: Ill Bloom’s investigation confirmed the use of this function in dependent wallets to generate BIP39 seed phrases. The subsequent hash function, or KDF, is unable to add the missing initial entropy.
Vulnerability Card
| Field | Meaning |
|---|---|
| Identifier | CVE-2026-71851; GHSA-rg76-677x-56q9 |
| Component | crypto-js, function CryptoJS.lib.WordArray.random() |
| Weakness class | CWE-331 — Insufficient Entropy; essentially also an insecure PRNG for secret values |
| Affected versions | Practically 3.x branch: from 3.1.2-4 to 4.0.0; fix – 4.0.0 and newer |
| Prerequisite for exploitation | The application effectively makes a vulnerable call to security-sensitive values: key, mnemonic, token, master secret, salt, or IV on which the secrecy depends. |
| The need for network access | No: After receiving a public indicator or verifiable result, an offline search for candidates is possible |
| The main damage | Recovering secret material, compromising a wallet or session, decrypting data with a weak key |
Applicability boundary. Presence crypto-js < 4.0.0 in the lock file alone does not prove exploitation. The reachability WordArray.random() and purpose of each result must be established.
Cryptanalytic reason
Cryptographic randomness isn’t “looking random,” but rather unpredictability to an adversary observing the system and its outputs. Math.random() CSPRNGs don’t have contracts: the implementation depends on the JavaScript engine, and its internal state and initialization aren’t intended to generate key material. The MWC add-on doesn’t turn a weak seed source into a CSPRNG.
H∞(X) = -log2(max_x Pr[X = x])
For brute-force security, the decisive value is the min-entropy H∞, not the buffer length. If 16 bytes are represented by 128 bits, but only approximately 2^39 128 states are accessible, their cryptanalytic strength is closer to 39 bits, not 128.
Quantitative assessment
| API request | Nominal size | Efficient space | Loss relative to face value | Average enumeration |
|---|---|---|---|---|
WordArray.random(16) | 128 bits | ≈ 2^39 | ≈ 89 bits | ≈ 2^38 candidates |
WordArray.random(32) | 256 bits | ≈ 2^47 | ≈ 209 bits | ≈ 2^46 candidates |
N_eff ≈ 2^h; W_avg ≈ 2^(h-1); T_avg = 2^(h-1) / R
Here h , is the effective entropy, R the measured speed of candidate verification per second. For example, at R = 10^8 [verifications/sec], the average search time for [is] 2^39 is about 1.5 hours, and for 2^47 [is] is about 16.3 days. Actual figures depend on the verification predicate, hardware, parallelism, number of addresses, and derivation path; they cannot be substituted by the stated key length.
Compromise chain
- The application calls
WordArray.random()to obtain “entropy”. - The output is used directly as a secret or is included in the generation of a BIP39 mnemonic.
- The adversary receives a verifiable reference: an address, a public key, a ciphertext with a known structure, a token, or another oracle.
- It enumerates a compact space of internal states/outputs and reproduces subsequent deterministic processing.
- A matching candidate reveals the seed, private key, or other secret; in the wallet, this allows transactions to be signed.
This is an example of a secret generation attack, not a cryptanalysis of SHA-256, PBKDF2, secp256k1, or BIP32. These primitives may remain mathematically sound, but they receive predictable input and therefore do not compensate for the lack of initial uncertainty.
Historical context
| Happening | Cryptanalytics lesson | Link to CVE-2026-71851 |
|---|---|---|
| Netscape SSL (1995) | The PRNG state, derived from time and other predictable parameters, allowed the key material to be recovered. | The danger of using a generator that is not designed for keys: a seemingly long key does not equal an unpredictable key. |
| Debian OpenSSL (2006–2008) | The random removal of the entropy source dramatically narrowed the set of possible keys; the keys became enumerable. | Illustrates the fundamental formula: security is determined by the size of the set of actually achievable secrets. |
| Android SecureRandom (2013) | Insufficient/incorrectly initialized randomness resulted in ECDSA nonce repetition and the risk of private key extraction. | Shows that ECC does not protect against RNG flaws, especially when randomness is involved in key or nonce generation. |
BIP39 vector
BIP39 encodes the entropy into a checksum mnemonic; then PBKDF2-HMAC-SHA512 obtains the seed, and BIP32 deterministically derives the key tree. All stages after the initial entropy selection are deterministic: they stretch and transform the data, but do not increase the set of initial variants.
|supp(F(X))| ≤ |supp(X)|, therefore H∞(F(X)) ≤ H∞(X)
The function F here combines BIP39, PBKDF2, and BIP32. Even if the final seed is 512 bits, its support does not exceed the power of the set of weak inputs; a “512-bit” result does not imply 512 bits of entropy.
Unsafe template
// УЯЗВИМЫЙ паттерн в проектах со старым crypto-js
const entropy = CryptoJS.lib.WordArray.random(16); // Нельзя для ключей/BIP39/токенов
// Ошибка архитектуры: длинный WordArray не доказывает CSPRNG-качество.
A practical example: a front-end wallet can locally generate 16 bytes, encode them into 12 BIP39 words, and display them to the user. If these 16 bytes originate from a vulnerable function, the candidate is verified against a known blockchain address; a BIP39 passphrase can only hamper the attack if it was specifically chosen with high entropy.
Safe implementation
// Браузер: ОС/браузерный CSPRNG
function secureBytes(n) {
const out = new Uint8Array(n);
globalThis.crypto.getRandomValues(out);
return out;
}
const entropy128 = secureBytes(16);
// Node.js: CSPRNG платформы
import { randomBytes } from 'node:crypto';
const entropy256 = randomBytes(32);
A practical example: when creating a BIP39 mnemonic, pass bytes from a CSPRNG to the mnemonic library, rather than generating them using an older version of a general-purpose crypto library. Generation should occur where a system randomness source is available and should not have a fallback to Math.random().
Audit and detection
# Инвентаризация зависимостей
npm ls crypto-js
npm audit
rg -n "CryptoJS\.lib\.WordArray\.random|WordArray\.random" .
rg -n '"crypto-js"|crypto-js@' package.json package-lock.json yarn.lock pnpm-lock.yaml
Check for more than just direct dependencies: a vulnerable package may arrive transitively and be wrapped in its own generation function. For each call found, document the version, execution path, type of generated object, creation time, and the presence of an external verifiable trace.
Response
- Immediately stop creating new secrets through the vulnerable path and upgrade
crypto-jsto 4.0.0 or later. - Replace all security-sensitive data generators with Web Crypto API or
node:crypto; prohibit fallback toMath.random()review and testing policies. - Treat previously created mnemonics, private keys, tokens, and symmetric keys as potentially compromised; revoke/reissue them.
- For wallets: Generate a new mnemonic with a CSPRNG on a trusted device, transfer assets to new addresses, and stop using the old seed phrase.
- Preserve investigation artifacts: lockfile versions, source code, generation timeframes, and secret release logs; do not log the secrets themselves.
Limitations of the analysis
The Miggo source page, available at the time of analysis, primarily contains a card shell and marketing blocks without any published technical details. Therefore, the actual portion of the article has been verified against the CVE entry and advisory; claims of specific exploitation apply only after verifying the actual data flow in the target application.
Sources
CVE-2026-71851: crypto-js Insufficient Entropy – technical card: https://douban.ru/cve-2026-71851-crypto-js-insufficient-entropy-technical-card/
- CVE Program: CVE-2026-71851 – Description of the affected function and implications for BIP39.
- GitLab Advisory Database: CVE-2026-71851 – Space evaluation
2^39and2^47, actual exploitability condition. - Miggo Vulnerability Database: CVE-2026-71851 – Original Issue, August 2026.
- GitHub Security Advisory GHSA-rg76-677x-56q9 and commit
b405ff597fb3ac76a7bdfbc72dca10ba1079b1d5are the primary technical references for the fix.
