Crypto-View

BlueWallet/BlueWallet

Readiness score
72 of 100
How this is calculated · previous scan 72
Cryptographic posture
Quantum-vulnerable 180 Already broken 2 Reduced margin 15 Could not be determined 4 Quantum-safe 4
To address95
Key establishment0
Inventory only1
Total findings206
What was analysed
Branch Not at a branch head The commit was given directly and is not the tip of any branch in the repository.
Commit 969b5718b0f351e5177b420ee7701725cdfa4920 Merge pull request #8827 from BlueWallet/chore/upgrade-arkade-os-sdks-0.4.55
Committed 2026-08-05 20:07 UTC
Scanned 2026-09-10 07:46 UTC 19 hours ago
Coverage 948 files, 1 java, 2 python, 440 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 this scan 969b5718b0f3 72 95
21 hours ago 2cd003338401 master 72 94 Compare
1 day ago 2cd003338401 master 72 94 Compare
1 day ago 2cd003338401 master 72 94 Compare
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 92 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:1154 keyPair = ECPair.fromWIF(this._getWifForAddress(String(input.address)));
  12. class/wallets/abstract-hd-electrum-wallet.ts:1459 const hdRoot = bip32.fromSeed(seed);
  13. class/wallets/abstract-hd-electrum-wallet.ts:1475 const keyPair = ECPair.fromWIF(wif);
  14. class/wallets/abstract-hd-electrum-wallet.ts:1496 const root = bip32.fromSeed(seed);
  15. class/wallets/abstract-hd-electrum-wallet.ts:1507 const seed = bip39.mnemonicToSeedSync(mnemonic, passphrase);
  16. class/wallets/abstract-hd-electrum-wallet.ts:1642 const keyPair = ECPair.fromWIF(inputsTemp[0].wif);
  17. class/wallets/abstract-hd-wallet.ts:82 return bip39.mnemonicToSeedSync(mnemonic, passphrase);
  18. class/wallets/hd-aezeed-wallet.ts:51 const root = bip32.fromSeed(this._getEntropyCached());
  19. class/wallets/hd-aezeed-wallet.ts:54 const child = root.derivePath(path).neutered();
  20. class/wallets/hd-aezeed-wallet.ts:97 const root = bip32.fromSeed(this._getEntropyCached());
  21. class/wallets/hd-aezeed-wallet.ts:98 const node = root.derivePath("m/84'/0'/0'");
  22. class/wallets/hd-aezeed-wallet.ts:103 const root = bip32.fromSeed(this._getEntropyCached());
  23. class/wallets/hd-aezeed-wallet.ts:104 const node = root.derivePath("m/84'/0'/0'");
  24. class/wallets/hd-aezeed-wallet.ts:142 const root = bip32.fromSeed(this._getEntropyCached());
  25. class/wallets/hd-aezeed-wallet.ts:144 const child = root.derivePath(path);
  26. class/wallets/hd-aezeed-wallet.ts:172 const root = bip32.fromSeed(this._getEntropyCached());
  27. class/wallets/hd-aezeed-wallet.ts:173 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:51 const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
  40. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:52 const xpub = root.derivePath("m/0'").neutered().toBase58();
  41. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:68 const node = bip32.fromBase58(xpub);
  42. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:84 const node = bip32.fromBase58(xpub);
  43. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:99 const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
  44. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:101 const child = root.derivePath(path);
  45. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:111 const hdNode = bip32.fromBase58(xpub);
  46. class/wallets/hd-segwit-electrum-seed-p2wpkh-wallet.ts:117 const hdNode = bip32.fromBase58(xpub);
  47. class/wallets/hd-segwit-p2sh-wallet.ts:64 const root = bip32.fromSeed(seed);
  48. class/wallets/hd-segwit-p2sh-wallet.ts:70 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:467 keyPair = ECPair.fromWIF(this.secret); // secret is WIF
  57. class/wallets/legacy-wallet.ts:627 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:186 bip32.fromBase58(xpub);
  62. class/wallets/multisig-hd-wallet.ts:196 bip32.fromBase58(xprv);
  63. class/wallets/multisig-hd-wallet.ts:263 const restored = bip32.fromBase58(MultisigHDWallet.convertMultisigXprvToRegularXprv(xprv));
  64. class/wallets/multisig-hd-wallet.ts:310 const hdNode = bip32.fromBase58(xpub);
  65. class/wallets/multisig-hd-wallet.ts:369 seed = bip39.mnemonicToSeedSync(mnemonic, passphrase);
  66. class/wallets/multisig-hd-wallet.ts:372 const root = bip32.fromSeed(seed);
  67. class/wallets/multisig-hd-wallet.ts:373 const child = root.derivePath(path).neutered();
  68. class/wallets/multisig-hd-wallet.ts:757 const hdNode0 = bip32.fromBase58(xpub);
  69. class/wallets/multisig-hd-wallet.ts:866 const hdNode0 = bip32.fromBase58(xpub);
  70. class/wallets/multisig-hd-wallet.ts:1030 let seed = bip39.mnemonicToSeedSync(cosigner, passphrase);
  71. class/wallets/multisig-hd-wallet.ts:1035 const hdRoot = bip32.fromSeed(seed);
  72. class/wallets/multisig-hd-wallet.ts:1077 const root = bip32.fromSeed(new Uint8Array(32));
  73. class/wallets/multisig-hd-wallet.ts:1079 root.derivePath(path);
  74. class/wallets/multisig-hd-wallet.ts:1174 hdRoot = bip32.fromBase58(xprv);
  75. class/wallets/multisig-hd-wallet.ts:1179 : bip39.mnemonicToSeedSync(cosigner, passphrase);
  76. class/wallets/multisig-hd-wallet.ts:1180 hdRoot = bip32.fromSeed(seed);
  77. class/wallets/multisig-hd-wallet.ts:1207 const child = hdRoot.derivePath(path);
  78. class/wallets/multisig-hd-wallet.ts:1209 const keyPair = ECPair.fromPrivateKey(child.privateKey);
  79. class/wallets/segwit-bech32-wallet.ts:25 const keyPair = ECPair.fromWIF(this.secret);
  80. class/wallets/segwit-bech32-wallet.ts:90 const keyPair = ECPair.fromWIF(this.secret);
  81. class/wallets/segwit-p2sh-wallet.ts:67 const keyPair = ECPair.fromWIF(this.secret);
  82. class/wallets/segwit-p2sh-wallet.ts:108 const keyPair = ECPair.fromWIF(this.secret);
  83. class/wallets/taproot-wallet.ts:56 const keyPair = ECPair.fromWIF(this.secret);
  84. class/wallets/taproot-wallet.ts:88 const keyPair = ECPair.fromWIF(this.secret);
  85. class/wallets/watch-only-wallet.ts:311 const hdNode = bip32.fromBase58(xpub);
  86. screen/settings/SelfTest.tsx:265 test path const seed = bip39.mnemonicToSeedSync(mnemonic);
  87. screen/settings/SelfTest.tsx:266 test path const root = bip32.fromSeed(seed);
  88. screen/settings/SelfTest.tsx:269 test path const child = root.derivePath(path);
  89. tests/integration/bip47.test.ts:91 test path const keyPair2 = ECPair.fromWIF(w._getWIFbyAddress('bc1q57nwf9vfq2qsl80q37wq5h0tjytsk95vgjq4fe') || '');
  90. tests/integration/bip47.test.ts:119 test path const keyPair = ECPair.fromWIF(w._getWIFbyAddress('bc1q57nwf9vfq2qsl80q37wq5h0tjytsk95vgjq4fe') || '');
  91. tests/unit/bip47.test.ts:87 test path const keyPair2 = ECPair.fromWIF(w._getWIFbyAddress('bc1q57nwf9vfq2qsl80q37wq5h0tjytsk95vgjq4fe') || '');
  92. 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. 179
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