From e7c1ed53f88410e47e8660418152e368e8348604 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Sat, 9 Aug 2025 01:16:01 -0700 Subject: [PATCH] Zero out sensitive data in worker from input message as it is processed. --- src/lib/wallet/safe.ts | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/lib/wallet/safe.ts b/src/lib/wallet/safe.ts index c39b9b6..3f93051 100644 --- a/src/lib/wallet/safe.ts +++ b/src/lib/wallet/safe.ts @@ -401,7 +401,11 @@ export class Safe { if (messageData.password != null && !(messageData.password instanceof ArrayBuffer)) { throw new TypeError('Password must be ArrayBuffer') } - const password = messageData.password + let password = messageData.password?.slice() + if (messageData.password instanceof ArrayBuffer) { + new Uint8Array(messageData.password).fill(0) + delete messageData.password + } // IV for crypto key, included if unlocking or generated if creating if (action === 'unlock' && !(messageData.iv instanceof ArrayBuffer)) { @@ -423,6 +427,10 @@ export class Safe { const key = password instanceof ArrayBuffer ? await this.#createAesKey(action === 'unlock' ? 'decrypt' : 'encrypt', password, keySalt) : undefined + if (password instanceof ArrayBuffer && !password.detached) { + new Uint8Array(password).fill(0) + password = undefined + } // Type of wallet if (messageData.type !== undefined && messageData.type !== 'BIP-44' && messageData.type !== 'BLAKE2b') { @@ -436,12 +444,16 @@ export class Safe { } // Seed to import - if (action === 'import' && 'seed' in message && !(messageData.seed instanceof ArrayBuffer)) { + if (action === 'import' && 'seed' in messageData && !(messageData.seed instanceof ArrayBuffer)) { throw new TypeError('Seed required to import wallet') } const seed = messageData.seed instanceof ArrayBuffer - ? messageData.seed + ? messageData.seed.slice() : undefined + if (messageData.seed instanceof ArrayBuffer) { + new Uint8Array(messageData.seed).fill(0) + delete messageData.seed + } // Mnemonic phrase to import if (action === 'import' && 'mnemonicPhrase' in message && typeof messageData.mnemonicPhrase !== 'string') { @@ -450,6 +462,7 @@ export class Safe { const mnemonicPhrase = typeof messageData.mnemonicPhrase === 'string' ? messageData.mnemonicPhrase : undefined + delete messageData.mnemonicPhrase // Mnemonic salt for mnemonic phrase to import if (action === 'import' && messageData.mnemonicSalt != undefined && typeof messageData.mnemonicSalt !== 'string') { @@ -458,6 +471,7 @@ export class Safe { const mnemonicSalt = typeof messageData.mnemonicSalt === 'string' ? messageData.mnemonicSalt : undefined + delete messageData.mnemonicSalt // Encrypted seed and possibly mnemonic if (action === 'unlock') { @@ -469,8 +483,12 @@ export class Safe { } } const encrypted = messageData.encrypted instanceof ArrayBuffer - ? messageData.encrypted + ? messageData.encrypted.slice() : undefined + if (messageData.encrypted instanceof ArrayBuffer) { + new Uint8Array(messageData.encrypted).fill(0) + delete messageData.encrypted + } // Index for child account to derive or sign if ((action === 'derive' || action === 'sign') && typeof messageData.index !== 'number') { @@ -492,6 +510,7 @@ export class Safe { const data = messageData.data instanceof ArrayBuffer ? messageData.data : undefined + delete messageData.data return { action, type, key, iv, keySalt, seed, mnemonicPhrase, mnemonicSalt, encrypted, index, data } } -- 2.47.3