Crypto-View

BlueWallet/BlueWallet

Readiness score
72 of 100
How this is calculated · previous scan 72
Cryptographic posture
Quantum-vulnerable 179 Already broken 2 Reduced margin 15 Could not be determined 4 Quantum-safe 4
To address94
Key establishment0
Inventory only1
Total findings205
What was analysed
Branch master
Commit 2cd003338401db350d91917a0c3d170ff9a926a8 Merge pull request #8904 from BlueWallet/fix-ios-keyboard-input-jump-large-title
Committed 2026-09-09 23:24 UTC
Scanned 2026-09-10 01:55 UTC 1 day ago
Coverage 955 files, 1 java, 4 python, 444 javascript

Earlier scans of this repository

13 scans · score 72 → 72 · compare any two
13 scans · 72 → 72 (unchanged). The filled point is the scan you are reading.
Scanned Commit Score To address
4 hours ago f04421fe1eb1 master 72 94 Compare
5 hours ago f04421fe1eb1 master 72 94 Compare
19 hours ago 969b5718b0f3 72 95 Compare
21 hours ago 2cd003338401 master 72 94 Compare
1 day ago 2cd003338401 master 72 94 Compare
1 day ago this scan 2cd003338401 master 72 94
1 day ago 2cd003338401 master 72 94 Compare
1 day ago 2cd003338401 master 72 94 Compare
3 days ago 7b5fef91cb38 master 72 94 Compare
3 days ago 7b5fef91cb38 master 72 94 Compare
4 days ago dd4d340fff10 master 72 94 Compare
10 days ago 06e94f0dcb98 master 72 94 Compare
11 days ago 969b5718b0f3 72 95 Compare

Every repository in this history is re-scanned weekly.

List of cryptographic assets

MD5 Already broken 2 places See details

Hash function in use

`createHash()` or `subtle.digest()`. The digest is read from the argument, so one rule covers the family: MD5 and SHA-1 are reported as broken, SHA-256 as a reduced margin, SHA-384 and above as inventory.

This is already unsafe today, with no quantum computer involved. Practical chosen-prefix collisions exist; MD5 has no remaining security as a digest.

What to do. SHA-256 as the floor, SHA-384 where the digest protects something long-lived.

  1. tests/custom-environment.js:11 test path const hash = require('crypto').createHash('md5').update(fullName).digest('hex');
  2. tests/custom-reporter.js:26 test path const hash = require('crypto').createHash('md5').update(testCaseResult.fullName).digest('hex');
js.hash · CWE-328
secp256k1256-bitsecg/secp256k1 Quantum-vulnerable Renamed import 91 places See details

Cryptocurrency key derivation

A BIP-32 derivation or a secp256k1 operation. Wallet keys are secp256k1, and on a public ledger the public key is usually already visible, so an attacker with a quantum computer does not have to wait to observe a signature.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer. Bitcoin-family keys are additionally exposed because public keys are published on-chain, so the attacker does not have to wait for a signature.

What to do. No standardised replacement exists for consensus-level signatures. Follow the protocol's own migration plan; an application cannot make this change alone.

  1. class/lnurl.ts:373 const publicKey = ecc.pointFromScalar(privateKey);
  2. class/lnurl.ts:377 const signature = ecc.signDER(hexToUint8Array(url.query.k1 as string), privateKey);
  3. class/multisig-cosigner.ts:184 bip32.fromBase58(xpub);
  4. class/payjoin-transaction.ts:38 const keyPair = ECPair.fromWIF(wif);
  5. class/payjoin-transaction.ts:83 const keyPair = ECPair.fromWIF(wif);
  6. class/wallets/abstract-hd-electrum-wallet.ts:198 const root = bip32.fromSeed(seed);
  7. class/wallets/abstract-hd-electrum-wallet.ts:200 const child = root.derivePath(path);
  8. class/wallets/abstract-hd-electrum-wallet.ts:212 const hdNode = bip32.fromBase58(xpub).derive(node);
  9. class/wallets/abstract-hd-electrum-wallet.ts:258 const root = bip32.fromSeed(seed);
  10. class/wallets/abstract-hd-electrum-wallet.ts:264 const child = root.derivePath(path).neutered();
  11. class/wallets/abstract-hd-electrum-wallet.ts:1094 keyPair = ECPair.fromWIF(this._getWifForAddress(String(input.address)));
  12. class/wallets/abstract-hd-electrum-wallet.ts:1373 const hdRoot = bip32.fromSeed(seed);
  13. class/wallets/abstract-hd-electrum-wallet.ts:1389 const keyPair = ECPair.fromWIF(wif);
  14. class/wallets/abstract-hd-electrum-wallet.ts:1410 const root = bip32.fromSeed(seed);
  15. class/wallets/abstract-hd-electrum-wallet.ts:1421 const seed = bip39.mnemonicToSeedSync(mnemonic, passphrase);
  16. class/wallets/abstract-hd-electrum-wallet.ts:1556 const keyPair = ECPair.fromWIF(inputsTemp[0].wif);
  17. class/wallets/abstract-hd-wallet.ts:80 return bip39.mnemonicToSeedSync(mnemonic, passphrase);
  18. class/wallets/hd-aezeed-wallet.ts:50 const root = bip32.fromSeed(this._getEntropyCached());
  19. class/wallets/hd-aezeed-wallet.ts:53 const child = root.derivePath(path).neutered();
  20. class/wallets/hd-aezeed-wallet.ts:93 const root = bip32.fromSeed(this._getEntropyCached());
  21. class/wallets/hd-aezeed-wallet.ts:94 const node = root.derivePath("m/84'/0'/0'");
  22. class/wallets/hd-aezeed-wallet.ts:99 const root = bip32.fromSeed(this._getEntropyCached());
  23. class/wallets/hd-aezeed-wallet.ts:100 const node = root.derivePath("m/84'/0'/0'");
  24. class/wallets/hd-aezeed-wallet.ts:138 const root = bip32.fromSeed(this._getEntropyCached());
  25. class/wallets/hd-aezeed-wallet.ts:140 const child = root.derivePath(path);
  26. class/wallets/hd-aezeed-wallet.ts:168 const root = bip32.fromSeed(this._getEntropyCached());
  27. class/wallets/hd-aezeed-wallet.ts:169 const node = root.derivePath("m/1017'/0'/6'/0/0");
  28. class/wallets/hd-legacy-breadwallet-wallet.ts:35 _node = this._node0 || (this._node0 = bip32.fromBase58(this.getXpub()).derive(node));
  29. class/wallets/hd-legacy-breadwallet-wallet.ts:38 _node = this._node1 || (this._node1 = bip32.fromBase58(this.getXpub()).derive(node));
  30. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:49 const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
  31. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:58 const node = bip32.fromBase58(this.getXpub());
  32. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:73 const node = bip32.fromBase58(this.getXpub());
  33. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:88 const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
  34. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:90 const child = root.derivePath(path);
  35. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:100 const hdNode = bip32.fromBase58(xpub);
  36. class/wallets/hd-legacy-electrum-seed-p2pkh-wallet.ts:106 const hdNode = bip32.fromBase58(xpub);
  37. class/wallets/hd-legacy-p2pkh-wallet.ts:55 const root = bip32.fromSeed(seed);
  38. class/wallets/hd-legacy-p2pkh-wallet.ts:61 const child = root.derivePath(path).neutered();
  39. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:49 const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
  40. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:50 const xpub = root.derivePath("m/0'").neutered().toBase58();
  41. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:63 const node = bip32.fromBase58(xpub);
  42. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:79 const node = bip32.fromBase58(xpub);
  43. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:94 const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
  44. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:96 const child = root.derivePath(path);
  45. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:106 const hdNode = bip32.fromBase58(xpub);
  46. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:112 const hdNode = bip32.fromBase58(xpub);
  47. class/wallets/hd-segwit-p2sh-wallet.ts:62 const root = bip32.fromSeed(seed);
  48. class/wallets/hd-segwit-p2sh-wallet.ts:68 const child = root.derivePath(path).neutered();
  49. class/wallets/hd-taproot-wallet.ts:28 const root = bip32.fromSeed(seed);
  50. class/wallets/hd-taproot-wallet.ts:34 const child = root.derivePath(path).neutered();
  51. class/wallets/hd-taproot-wallet.ts:70 const hdNode = bip32.fromBase58(xpub);
  52. class/wallets/hd-taproot-wallet.ts:80 const hdNode = bip32.fromBase58(xpub);
  53. class/wallets/legacy-wallet.ts:69 this.secret = ECPair.makeRandom({ rng: () => buf }).toWIF();
  54. class/wallets/legacy-wallet.ts:76 this.secret = ECPair.fromPrivateKey(user).toWIF();
  55. class/wallets/legacy-wallet.ts:83 const keyPair = ECPair.fromWIF(this.secret);
  56. class/wallets/legacy-wallet.ts:466 keyPair = ECPair.fromWIF(this.secret); // secret is WIF
  57. class/wallets/legacy-wallet.ts:626 const keyPair = ECPair.fromWIF(wif);
  58. class/wallets/lightning-ark-wallet.ts:144 const seed = bip39.mnemonicToSeedSync(mnemonic);
  59. class/wallets/lightning-ark-wallet.ts:149 const root = bip32.fromSeed(seed);
  60. class/wallets/lightning-ark-wallet.ts:151 const child = root.derivePath(path);
  61. class/wallets/multisig-hd-wallet.ts:187 bip32.fromBase58(xpub);
  62. class/wallets/multisig-hd-wallet.ts:197 bip32.fromBase58(xprv);
  63. class/wallets/multisig-hd-wallet.ts:264 const restored = bip32.fromBase58(MultisigHDWallet.convertMultisigXprvToRegularXprv(xprv));
  64. class/wallets/multisig-hd-wallet.ts:314 const hdNode = bip32.fromBase58(xpub);
  65. class/wallets/multisig-hd-wallet.ts:373 seed = bip39.mnemonicToSeedSync(mnemonic, passphrase);
  66. class/wallets/multisig-hd-wallet.ts:376 const root = bip32.fromSeed(seed);
  67. class/wallets/multisig-hd-wallet.ts:377 const child = root.derivePath(path).neutered();
  68. class/wallets/multisig-hd-wallet.ts:751 const hdNode0 = bip32.fromBase58(xpub);
  69. class/wallets/multisig-hd-wallet.ts:1008 : bip39.mnemonicToSeedSync(cosigner, passphrase);
  70. class/wallets/multisig-hd-wallet.ts:1009 hdRoots.push(bip32.fromSeed(seed));
  71. class/wallets/multisig-hd-wallet.ts:1055 const root = bip32.fromSeed(new Uint8Array(32));
  72. class/wallets/multisig-hd-wallet.ts:1057 root.derivePath(path);
  73. class/wallets/multisig-hd-wallet.ts:1153 hdRoot = bip32.fromBase58(xprv);
  74. class/wallets/multisig-hd-wallet.ts:1158 : bip39.mnemonicToSeedSync(cosigner, passphrase);
  75. class/wallets/multisig-hd-wallet.ts:1159 hdRoot = bip32.fromSeed(seed);
  76. class/wallets/multisig-hd-wallet.ts:1190 const child = hdRoot.derivePath(path);
  77. class/wallets/multisig-hd-wallet.ts:1192 const keyPair = ECPair.fromPrivateKey(child.privateKey);
  78. class/wallets/segwit-bech32-wallet.ts:25 const keyPair = ECPair.fromWIF(this.secret);
  79. class/wallets/segwit-bech32-wallet.ts:89 const keyPair = ECPair.fromWIF(this.secret);
  80. class/wallets/segwit-p2sh-wallet.ts:67 const keyPair = ECPair.fromWIF(this.secret);
  81. class/wallets/segwit-p2sh-wallet.ts:107 const keyPair = ECPair.fromWIF(this.secret);
  82. class/wallets/taproot-wallet.ts:52 const keyPair = ECPair.fromWIF(this.secret);
  83. class/wallets/taproot-wallet.ts:84 const keyPair = ECPair.fromWIF(this.secret);
  84. class/wallets/watch-only-wallet.ts:310 const hdNode = bip32.fromBase58(xpub);
  85. screen/settings/SelfTest.tsx:265 test path const seed = bip39.mnemonicToSeedSync(mnemonic);
  86. screen/settings/SelfTest.tsx:266 test path const root = bip32.fromSeed(seed);
  87. screen/settings/SelfTest.tsx:269 test path const child = root.derivePath(path);
  88. tests/integration/bip47.test.ts:91 test path const keyPair2 = ECPair.fromWIF(w._getWIFbyAddress('bc1q57nwf9vfq2qsl80q37wq5h0tjytsk95vgjq4fe') || '');
  89. tests/integration/bip47.test.ts:119 test path const keyPair = ECPair.fromWIF(w._getWIFbyAddress('bc1q57nwf9vfq2qsl80q37wq5h0tjytsk95vgjq4fe') || '');
  90. tests/unit/bip47.test.ts:87 test path const keyPair2 = ECPair.fromWIF(w._getWIFbyAddress('bc1q57nwf9vfq2qsl80q37wq5h0tjytsk95vgjq4fe') || '');
  91. tests/unit/ecc.test.ts:51 test path const rez2 = ecc.privateAdd(
js.wallet.keys · CWE-327
ECDSA Quantum-vulnerable Renamed import 1 place See details

Noble cryptography library in use

A `@noble/curves`, `@noble/secp256k1` or `@noble/ed25519` import. These are the modern audited JavaScript curve implementations, and every curve they offer is broken by Shor. `@noble/hashes` is inventoried separately and is not quantum-vulnerable.

A quantum computer of sufficient size breaks this completely. It has to be replaced, not tuned. Broken by Shor's algorithm on a cryptographically relevant quantum computer.

What to do. `@noble/post-quantum` provides ML-KEM and ML-DSA from the same authors.

  1. blue_modules/noble_ecc.ts:143 throwToNull(() => necc.getPublicKey(sk, defaultTrue(compressed))),
js.noble · CWE-327
unknown Could not be determined 1 place See details

Cryptographic library in the dependency manifest

A dependency known to implement classical asymmetric cryptography. Its presence is inventory, not a finding about this codebase: the library may never be called with a quantum-vulnerable algorithm.

The project depends on a cryptography library. Listed so the inventory is complete; it is not by itself a problem.

What to do. Check the version. Several of these libraries have shipped ML-KEM and ML-DSA support since 2024, so the migration may need an upgrade rather than a replacement.

  1. package.json:135 "bitcoinjs-lib": "7.0.1",
dep.crypto-library
CSPRNG Quantum-safe 1 place See details

Random number generation

`crypto.randomBytes()`, `randomUUID()` or `getRandomValues()`. A platform CSPRNG is not a quantum exposure; it is recorded because an inventory that omits the randomness source is incomplete. `Math.random()` is a separate, present-day defect.

This is where the software gets its random numbers. Quantum computers do not weaken it.

What to do. No action.

  1. class/rng.ts:20 rnCrypto.getRandomValues(bytes);
js.rng
scrypt Quantum-safe 1 place See details

Password hashing or key derivation

A password hashing or key derivation function. Not a quantum exposure, and part of the inventory: a cryptographic bill of materials that omits how passwords are stored is not complete.

This is how passwords are stored. Quantum computers do not meaningfully weaken it.

What to do. Argon2id for new work. PBKDF2 needs a high iteration count to stay defensible.

  1. screen/settings/SelfTest.tsx:309 test path const hex = await BlueCrypto.scrypt('717765727479', '4749345a22b23cf3', 64, 8, 8, 32); // using non-default parameters to speed it up (not-bip38 compliant)
js.kdf

Cryptographic assets

Algorithm Assessment What it means Occurrences
secp256k1 Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. Bitcoin-family keys are additionally exposed because public keys are published on-chain, so the attacker does not have to wait for a signature. 178
SHA-256 Reduced margin Pre-image resistance falls to about 128 bits of quantum work. Adequate for most uses; SHA-384 restores the full margin where a signature must last decades. 15
unknown Could not be determined The algorithm could not be established from the source - chosen at runtime, or decided somewhere this scan does not reach. 4
MD5 Already broken Practical chosen-prefix collisions exist; MD5 has no remaining security as a digest. 2
ChaCha20-Poly1305 Quantum-safe No known quantum algorithm changes the security margin. 2
ECDSA Quantum-vulnerable Broken by Shor's algorithm on a cryptographically relevant quantum computer. 1
CSPRNG Quantum-safe A cryptographically secure random number generator provided by the platform. Not weakened by a quantum computer. 1
scrypt Quantum-safe No known quantum algorithm changes the security margin. 1

Imported cryptographic libraries

Library Files
bitcoinjs-lib — the Bitcoin protocol 59
@noble/hashes — hash functions 15
crypto — the Node crypto module 4
@noble/ciphers — symmetric encryption 2