
Document type: scientific and technical paper Subject: weak pseudorandom number generator (PRNG), BIP39 and deterministic wallet compromise.
Annotation
CVE-2026-71851 fixes a critical class of cryptographic flaw: substitution of cryptographically strong randomness with an internal deterministic generator. In versions crypto-js prior to 4.0.0, the function CryptoJS.lib.WordArray.random() used a variant of Multiply-With-Carry (MWC), initialized via [ Math.random()], rather than the operating system’s cryptographic entropy source.
The cryptanalytic consequence is not a “break of SHA-256,” BIP39, PBKDF2, or secp256k1. The original entropy is weakened: the nominal 128 and 256 bits are reduced to approximately the enumeration spaces of 2^39 and 2^47. If this function was used to generate a BIP39 mnemonic, enumeration of the states can allow one to recover the phrase, derived seed, HD keys, and asset management.
Vulnerability Card
| Category | Content | Cryptanalytic meaning |
|---|---|---|
| Identifier | CVE-2026-71851; related advisory: GHSA-rg76-677x-56q9. | Allows you to link SCA, SBOM, build logs, and incident investigation results to a single cause. |
| Component | JavaScript library crypto-js, function CryptoJS.lib.WordArray.random(). | The risk is associated specifically with the function call for secrets, not with each library import. |
| Affected range | Versions before 4.0.0; the defective path was introduced in 3.1.2-4 and was present in almost the entire 3.x branch. | The period of use of old browser and mobile assemblies becomes the subject of a retrospective audit. |
| Root cause | Custom MWC PRNG, seeded Math.random(), instead of CSPRNG. | The deterministic internal state limits the number of achievable outputs. |
| Upstream fix | crypto-js 4.0.0 returns the use of the native cryptographic randomness source. | The update protects future generations, but does not change already generated keys and mnemonics. |
| Debian bookworm | The source package cryptojs, version 3.1.2+dfsg-3, is marked as vulnerable. | The distribution package stores vulnerable code if the application uses an insecure function for sensitive material. |
| Debian’s status is unstable | The tracker indicates (unfixed). | The presence of a package in the repository cannot be interpreted as the presence of a backport fix. |
| Debian Notes | For bookworm and bullseye: <postponed>, “Minor issue, low popcon”. | Prioritization of package support is not an assessment of damage to a specific wallet or service. |
Applicability boundary. The presence of a dependency crypto-js < 4.0.0 alone does not prove exploitation. A verifiable data flow is required: the call WordArray.random() must generate a security-sensitive value—a mnemonic, private key, nonce, token, salt with unpredictability requirements, or another secret.
Defect model
A pseudorandom generator can be represented as a deterministic automaton:
S_{i+1} = F(S_i), R_i = G(S_i)
Here S_i , is the internal state, R_i are the generated words. Cryptographic suitability requires that the initial state be obtained from a source with high unpredictability and that observations do not allow one to reconstruct the state or predict subsequent values.
MWC is a fast statistical PRNG, but a statistical “random-like” distribution is not equivalent to cryptographic unpredictability. In the code path under consideration, weak initialization Math.random() limits the effective number of possible sequences; expanding the output to 16 or 32 bytes does not create new entropy if it is all deterministically generated by a small seed state.
Formal loss of stability
Let the application request n a bit, but the set of actually achievable results is at most 2^k. Then the cryptanalytic strength is bounded by k, not by n:
H_min(X) = -log_2(max_x Pr[X=x]) approximately H_min(X) approximately kW approximately min(n, k)
For this CVE, the estimated gains are: for a 128-bit query k approximately 39, , and for a 256-bit query k approximately 47, . Thus, the idealized attacker’s gain relative to a brute-force attack is approximately:
2^(128-39) = 2^89 for 128-bit input;2^(256-47) = 2^209 for 256-bit input.
The expected number of samples in a uniform search is approximately equal to half the space:
E[N] approximately 2^(k-1)
This doesn’t guarantee practical cost in a specific implementation: the time depends on the exact generator variant, platform behavior Math.random(), the ability to replay the path, and an effective verification oracle. However, the fundamental flaw—entropy collapse—eliminates the claimed 128/256-bit security bound.
Relationship with BIP39
BIP39 encodes the raw entropy ENT into a readable mnemonic. The standard allows ENT for 128 to 256 bits; the checksum has a length of CS = ENT / 32, then the string ENT || CS is divided into 11-bit indices into a 2048-word dictionary.
CS = ENT / 32MS = (ENT + CS) / 11Mnemonic = Encode_2048(ENT || MSB_CS(SHA256(ENT)))
| Initial entropy | Checksum | Length of mnemonic | Effective resilience in a vulnerable environment |
|---|---|---|---|
| 128 bits | 4 bits | 12 words | Around 2^39 candidates, not 2^128. |
| 256 bits | 8 bits | 24 words | Around 2^47 candidates, not 2^256. |
The BIP39 checksum doesn’t add secret entropy: it’s deterministically calculated from ENT. Therefore, it’s suitable for filtering out invalid phrases, but it doesn’t save mnemonics whose initial entropy was predictable.
Converting the mnemonic to a seed also does not restore the lost randomness:
seed = PBKDF2-HMAC-SHA512(password=mnemonic_NFKD, salt="mnemonic" || passphrase_NFKD, c=2048, dkLen=64)
PBKDF2 is deterministic. Given a known candidate mnemonic generation algorithm, an attacker derives the same seed, then applies a BIP32/compatible derivation and matches known addresses, public keys, balances, or transaction activity.
Cryptanalysis script
Below is a model for a legitimate audit and response, not a guide to attacking someone else’s assets. The goal is to determine whether secrets for a specific product were obtained through an unsafe source.
- Inventory: capture SBOM, lock files, npm artifacts, Debian packages, and frontend/mobile build versions.
- Data flow analysis: find calls
CryptoJS.lib.WordArray.random()and see if the output is fed to a BIP39 generator, keys, tokens, or cryptographic nonces. - Temporal attribution: Determine on which releases and dates secrets were released to users through a vulnerable code path.
- Testbed verification: reproduce the generation with test keys only, recording the version, runtime, and platform.
- Risk check: Match derived test identifiers against a control set without extracting and publishing the actual mnemonics.
- Remediation: replace CSPRNG, issue new mnemonics/keys, transfer assets, and revoke old credentials.
// Антипаттерн: исторически опасно для ключей, mnemonics и токенов
const entropy = CryptoJS.lib.WordArray.random(32);
// Предпочтительно в современных браузерах: системный CSPRNG Web Crypto API
const entropyBytes = new Uint8Array(32);
crypto.getRandomValues(entropyBytes);
// Предпочтительно в Node.js: системный CSPRNG
import { randomBytes } from 'node:crypto';
const entropyNode = randomBytes(32);
This example illustrates the principle, not a complete BIP39 generator. In a real product, you should use a proven mnemonic library, test with BIP39 vectors, and avoid home-made cryptographic “gluing” of bytes, hashes, and dictionaries.
Historical parallels
| Happening | General Cryptanalytic Lesson | Link to CVE-2026-71851 |
|---|---|---|
| Debian OpenSSL (2006–2008) | A random bug in a patch reduced the available key entropy; the consequences required a mass recall and regeneration of key material. | As here, the mathematical properties of RSA/DSA were not “broken”: the danger arose before the cryptographic primitive was applied, at the secret generation stage. |
| Android SecureRandom / Bitcoin Wallets (2013) | Insufficiently predictable randomness in ECDSA nonce generation can reveal the private key via signatures. | The failure point is different—nonce instead of BIP39 entropy—but the general principle is the same: the protocol’s strength is limited by the quality of randomness. |
| Dual_EC_DRBG (public discussions 2007–2013) | The generator may have an acceptable appearance, but the underlying predictability of its state destroys trust in any secret built on its output. | Demonstrates why the “output looks random” criterion is insufficient without a state model, seed, and backtracking/prediction resistance. |
| Weak web PRNGs in sessions and reset tokens | A predictable token turns authentication into a search task in a limited space. | The vulnerable function is dangerous not only for wallets: secrets that require unpredictability are also at risk. |
Historically, cryptosystems often fail not where elliptic curves or hash functions are used, but at the boundary between deterministic software and the source of entropy. Therefore, PRNG analysis is an independent part of the audit, not a secondary code quality check.
Impact on Debian
The Debian Security Tracker bookworm lists the source package cryptojs version 3.1.2+dfsg-3 with the status for vulnerable. The bookworm entry bullseye is marked postponed with the comment “Minor issue, low popcon”; the line for unstable indicates the status unfixed.
These labels should be read as distribution-specific information, not as a measure of actual criticality for a specific system. If a package is in the wallet, key, or token generation chain, the local risk assessment should consider its purpose, generation time, number of secrets affected, and the availability of the verification oracle.
Investigation methodology
| Question | Proof | Practical solution |
|---|---|---|
| Is there a vulnerable library present? | package-lock.json, yarn.lock, pnpm-lock.yaml, SBOM, Debian versions. | Create a time map of dependencies, including transitive ones. |
| Was a dangerous function used? | Sources, minified bundles, source maps, CI logs, code search. | Search for exact symbol WordArray.random and aliases after assembly. |
| Was the secret sensitive? | Data-flow up to BIP39, key, nonce, reset-token, session-id. | Separate demo, decorative and cryptographically significant calls. |
| What secrets are affected? | Application versions, release dates, telemetry, migration records. | Treat all secrets created in a vulnerable way as compromised until proven otherwise. |
| What to do after the update? | Confirming the new CSPRNG and rotation. | Update the code and dependencies, then regenerate secrets; for wallets, create a new phrase in a trusted environment and transfer funds. |
Engineering measures
- Use the system CSPRNG: Web Crypto API
crypto.getRandomValues()in the browser andnode:crypto.randomBytes()in Node.js. - Disable custom PRNGs for key generation, BIP39 entropy, ECDSA nonce, recovery tokens, and session identifier.
- Enable SCA/SBOM checking for npm and Debian dependencies; check not only the version but also the reachability of the vulnerable function.
- Separate “patching” and “rotation”: updating removes future generation, but does not increase the entropy of existing secrets.
- Conduct a cryptographic code review for each random value generation point and record the entropy source in the design documentation.
- Do not share seed phrases, private keys, or production logs with third-party scanners, cloud notebooks, or ticketing systems.
Limitations of the analysis
The estimates 2^39 characterize 2^47 the effective space specified in the advisory and do not represent a universal time for a successful attack. Actual feasibility depends on the reproducibility of the environment, the JavaScript engine implementation, the number of generated secrets, the derivation parameters, and whether the researcher can legitimately verify the candidate.
It’s also a mistake to assume that any wallet that has ever connected crypto-jsis automatically compromised. A valid conclusion requires confirmation of the specific call WordArray.random() to security-sensitive data in the affected release.
Conclusion
CVE-2026-71851 is a prime example of a catastrophic loss of cryptographic security due to flawed randomness generation. BIP39, SHA-256, PBKDF2-HMAC-SHA512, and HD derivation may work fully as specified, but are unable to compensate for entropy that was not present to begin with.
For owners of affected applications, the priority is not only to upgrade crypto-js to version 4.0.0 or higher, but also to inventory previously created secrets and safely rotate them. For Debian package maintainers and web application developers, the key lesson is that the source of randomness should be a system-wide CSPRNG, not a statistically plausible PRNG.
Sources
Debian Security Tracker – CVE-2026-71851: https://moneycome.ru/debian-security-tracker-cve-2026-71851/
- Debian Security Tracker. CVE-2026-71851 . https://security-tracker.debian.org/tracker/CVE-2026-71851
- GitHub Security Advisory. GHSA-rg76-677x-56q9: CryptoJS.lib.WordArray.random() uses a weak PRNG (Ill Bloom) . https://github.com/brix/crypto-js/security/advisories/GHSA-rg76-677x-56q9
- Bitcoin Improvement Proposals. BIP-0039: Mnemonic code for generating deterministic keys . https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
- Debian OpenSSL predictable PRNG incident: DSA-1571 and related Debian Security documentation.
- Android Bitcoin wallet random-number incident, 2013: Bitcoin Security Project analysis and wallet update announcements.
