From ab3f306a700d0dd4cebfbce033ea13e43ae05808 Mon Sep 17 00:00:00 2001 From: Dadam Rishikesh Reddy Date: Fri, 14 Aug 2026 18:00:56 +0530 Subject: [PATCH] chore(express): remove leaked test wallet credentials TICKET: WCI-1293 --- .gitignore | 3 ++ modules/express/EXTERNAL_SIGNER.md | 8 ++-- modules/express/encryptedPrivKeys.json | 3 -- modules/express/test/unit/bitgoExpress.ts | 2 +- .../test/unit/clientRoutes/externalSign.ts | 18 +++++---- .../test/unit/clientRoutes/signPayload.ts | 39 ++++++++----------- .../express/test/unit/typedRoutes/coinSign.ts | 24 ++++-------- .../test/unit/typedRoutes/generateShareTSS.ts | 23 ++++------- .../unit/typedRoutes/ofcExtSignPayload.ts | 16 ++++---- 9 files changed, 57 insertions(+), 79 deletions(-) delete mode 100644 modules/express/encryptedPrivKeys.json diff --git a/.gitignore b/.gitignore index 8a49c9603c..49c7744965 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ coverage .claude/agents/* !.claude/agents/*.md .cursor/ +# Prevent committing encrypted private key fixtures generated by fetchEncryptedPrivKeys.ts +encryptedPrivKeys.json +modules/express/encryptedPrivKeys.json diff --git a/modules/express/EXTERNAL_SIGNER.md b/modules/express/EXTERNAL_SIGNER.md index 642844ada6..af2539e268 100644 --- a/modules/express/EXTERNAL_SIGNER.md +++ b/modules/express/EXTERNAL_SIGNER.md @@ -18,8 +18,8 @@ Here is an example json file containing two wallet IDs and their corresponding e ``` { -"61f039aad587c2000745c687373e0fa9":"{\"iv\":\"+1u1Y9cvsYuRMeyH2slnXQ==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"54kOXTqJ9mc=\",\"ct\":\"JF5wQ82wa1dYyFxFlbHCvK4a+A6MTHdhOqc5uXsz2icWhkY2Lin/3Ab8ZwvwDaR1JYKmC/g1gXIGwVZEOl1M/bRHY420h7sDtmTS6Ebse5NWbF0ItfUJlk6HVATGa+C6mkbaVxJ4kQW/ehnT3riqzU069ATPz8E=\"}", -"61fb21819c54dd000755f8de3a18e46f":"{\"iv\":\"ULAkh1Ia2B2oJbVWRt+xMw==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"SVkVei5M1qU=\",\"ct\":\"NxfG1HQWGcrwCHkQh8DKeMaZrRic+SSBQHtuOSsSJzW5MDOpwqDta8PDdh52lp9eqtaY+CGN6rPhaGbeZDrEyV2PoBGeb48GicMTVAehkyoF9mr8edtsWDCxcmmde+1zv3czy2n/bgXYNGvX39D30GDRpfovSYc=\"}" +"":"", +"":"" } ``` @@ -71,8 +71,8 @@ Set as an environment variable in the format `WALLET__PASSPHRASE`. Not The environment variable can be set using `export`. For example, the wallet passphrases for the private keys above can be set with the following: ``` -export WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE=wDX058%c4plL1@pP -export WALLET_61fb21819c54dd000755f8de3a18e46f_PASSPHRASE=wDX058%c4plL1@pP +export WALLET__PASSPHRASE= +export WALLET__PASSPHRASE= ``` ### External signer mode configuration values diff --git a/modules/express/encryptedPrivKeys.json b/modules/express/encryptedPrivKeys.json deleted file mode 100644 index fa9742e4d4..0000000000 --- a/modules/express/encryptedPrivKeys.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "61f039aad587c2000745c687373e0fa9": "{\"iv\":\"/Gnh+Ip1G+IOhy+Cms+umQ==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"FYnd1xwReTw=\",\"ct\":\"vgnCvdJ1Z9sqeV6urYxNsscwnkB/6eSPsZhzaW4Cuc7RKEY1uWNlleR0Tjtd8nlQuhsA5UXFpOID3lHHHjPDvB+jWtRm08I2F+HNGYuklWG12vIiSrY2KnkYRJkyCghn5Pq3iEimQb9M2kkwj5wf4EtfAiz9jsY=\"}" -} \ No newline at end of file diff --git a/modules/express/test/unit/bitgoExpress.ts b/modules/express/test/unit/bitgoExpress.ts index fc9cdbd06b..d12a60b12a 100644 --- a/modules/express/test/unit/bitgoExpress.ts +++ b/modules/express/test/unit/bitgoExpress.ts @@ -27,7 +27,7 @@ proxyquire.noPreserveCache(); describe('Bitgo Express', function () { describe('server initialization', function () { const validPrvJSON = - '{"61f039aad587c2000745c687373e0fa9":"xprv9s21ZrQH143K3EuPWCBuqnWxydaQV6et9htQige4EswvcHKEzNmkVmwTwKoadyHzJYppuADB7Us7AbaNLToNvoFoSxuWqndQRYtnNy5DUY2"}'; + '{"a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6":"xprv9s21ZrQH143K3EuPWCBuqnWxydaQV6et9htQige4EswvcHKEzNmkVmwTwKoadyHzJYppuADB7Us7AbaNLToNvoFoSxuWqndQRYtnNy5DUY2"}'; const validLightningSignerConfigJSON = '{"fakeid":{"url": "https://127.0.0.1:8080","tlsCert":"dummy"}}'; it('should require NODE_ENV to be production when running against prod env', function () { diff --git a/modules/express/test/unit/clientRoutes/externalSign.ts b/modules/express/test/unit/clientRoutes/externalSign.ts index d5a403e663..bdebf72471 100644 --- a/modules/express/test/unit/clientRoutes/externalSign.ts +++ b/modules/express/test/unit/clientRoutes/externalSign.ts @@ -84,12 +84,11 @@ describe('External signer', () => { let mpcEcdsa: Ecdsa; let hdTree: HDTree; - const walletId = '61f039aad587c2000745c687373e0fa9'; - const walletPassword = 'wDX058%c4plL1@pP'; + const walletId = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'; + const walletPassword = 'test-wallet-passphrase'; const secret = 'xprv9s21ZrQH143K3EuPWCBuqnWxydaQV6et9htQige4EswvcHKEzNmkVmwTwKoadyHzJYppuADB7Us7AbaNLToNvoFoSxuWqndQRYtnNy5DUY2'; - const validPrv = - '{"61f039aad587c2000745c687373e0fa9":"{\\"iv\\":\\"+1u1Y9cvsYuRMeyH2slnXQ==\\",\\"v\\":1,\\"iter\\":10000,\\"ks\\":256,\\"ts\\":64,\\"mode\\":\\"ccm\\",\\"adata\\":\\"\\",\\"cipher\\":\\"aes\\",\\"salt\\":\\"54kOXTqJ9mc=\\",\\"ct\\":\\"JF5wQ82wa1dYyFxFlbHCvK4a+A6MTHdhOqc5uXsz2icWhkY2Lin/3Ab8ZwvwDaR1JYKmC/g1gXIGwVZEOl1M/bRHY420h7sDtmTS6Ebse5NWbF0ItfUJlk6HVATGa+C6mkbaVxJ4kQW/ehnT3riqzU069ATPz8E=\\"}"}'; + let validPrv: string; before(async function () { if (!nock.isActive()) { @@ -99,6 +98,13 @@ describe('External signer', () => { bitgo = TestBitGo.decorate(BitGo, { env: 'test' }); bitgo.initializeTestVars(); + const encryptedPrv = await bitgo.encrypt({ + password: walletPassword, + input: secret, + encryptionVersion: 1, + }); + validPrv = JSON.stringify({ [walletId]: encryptedPrv }); + bgUrl = common.Environments[bitgo.getEnv()].uri; hdTree = await Ed25519BIP32.initialize(); MPC = await Eddsa.initialize(hdTree); @@ -122,9 +128,7 @@ describe('External signer', () => { it('should read an encrypted prv from signerFileSystemPath and pass it to coin.signTransaction', async () => { const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv); - const envStub = sinon - .stub(process, 'env') - .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword }); + const envStub = sinon.stub(process, 'env').value({ [`WALLET_${walletId}_PASSPHRASE`]: walletPassword }); const signTransactionStub = sinon .stub(Coin.Btc.prototype, 'signTransaction') .resolves({ txHex: 'signedTx', txRequestId: '' } as SignedTransaction); diff --git a/modules/express/test/unit/clientRoutes/signPayload.ts b/modules/express/test/unit/clientRoutes/signPayload.ts index 92808081e7..b8fb7992fe 100644 --- a/modules/express/test/unit/clientRoutes/signPayload.ts +++ b/modules/express/test/unit/clientRoutes/signPayload.ts @@ -142,12 +142,11 @@ describe('Sign an arbitrary payload with trading account key', function () { describe('With the handler to sign an arbitrary payload in external signing mode', () => { let bitgo: BitGo; - const walletId = '61f039aad587c2000745c687373e0fa9'; - const walletPassword = 'wDX058%c4plL1@pP'; + const walletId = 'a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6'; + const walletPassword = 'test-wallet-passphrase'; const secret = 'xprv9s21ZrQH143K3EuPWCBuqnWxydaQV6et9htQige4EswvcHKEzNmkVmwTwKoadyHzJYppuADB7Us7AbaNLToNvoFoSxuWqndQRYtnNy5DUY2'; - const validPrv = - '{"61f039aad587c2000745c687373e0fa9":"{\\"iv\\":\\"+1u1Y9cvsYuRMeyH2slnXQ==\\",\\"v\\":1,\\"iter\\":10000,\\"ks\\":256,\\"ts\\":64,\\"mode\\":\\"ccm\\",\\"adata\\":\\"\\",\\"cipher\\":\\"aes\\",\\"salt\\":\\"54kOXTqJ9mc=\\",\\"ct\\":\\"JF5wQ82wa1dYyFxFlbHCvK4a+A6MTHdhOqc5uXsz2icWhkY2Lin/3Ab8ZwvwDaR1JYKmC/g1gXIGwVZEOl1M/bRHY420h7sDtmTS6Ebse5NWbF0ItfUJlk6HVATGa+C6mkbaVxJ4kQW/ehnT3riqzU069ATPz8E=\\"}"}'; + let validPrv: string; const payload = { this: { @@ -157,16 +156,20 @@ describe('With the handler to sign an arbitrary payload in external signing mode }, }; - before(() => { + before(async () => { bitgo = new BitGo({ env: 'test' }); + const encryptedPrv = await bitgo.encrypt({ + password: walletPassword, + input: secret, + encryptionVersion: 1, + }); + validPrv = JSON.stringify({ [walletId]: encryptedPrv }); }); it('should return a payload signed with trading account key read from the local file system', async () => { const stubbedSignature = Buffer.from('mysign'); const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv); - const envStub = sinon - .stub(process, 'env') - .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword }); + const envStub = sinon.stub(process, 'env').value({ [`WALLET_${walletId}_PASSPHRASE`]: walletPassword }); const signMessageStub = sinon.stub(Coin.Ofc.prototype, 'signMessage').resolves(stubbedSignature); @@ -248,9 +251,7 @@ describe('With the handler to sign an arbitrary payload in external signing mode it('should prioritize request body passphrase over environment variable', async () => { const stubbedSignature = Buffer.from('mysign'); const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv); - const envStub = sinon - .stub(process, 'env') - .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword }); + const envStub = sinon.stub(process, 'env').value({ [`WALLET_${walletId}_PASSPHRASE`]: walletPassword }); const signMessageStub = sinon.stub(Coin.Ofc.prototype, 'signMessage').resolves(stubbedSignature); @@ -290,7 +291,7 @@ describe('With the handler to sign an arbitrary payload in external signing mode }); describe('With invalid setup', () => { - const invalidPrv = '{"61f039aad587c2000745c687373e0fa9":"invalid"}'; + const invalidPrv = JSON.stringify({ [walletId]: 'invalid' }); it('should throw an error with missing wallet passphrase in env', async () => { const req = { @@ -306,14 +307,12 @@ describe('With the handler to sign an arbitrary payload in external signing mode } as unknown as ExpressApiRouteRequest<'express.v2.ofc.extSignPayload', 'post'>; await handleV2OFCSignPayloadInExtSigningMode(req).should.be.rejectedWith( - 'Could not find wallet passphrase WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE in environment' + `Could not find wallet passphrase WALLET_${walletId}_PASSPHRASE in environment` ); }); it('should throw an error with undefined signerFileSystemPath in env', async () => { - const envStub = sinon - .stub(process, 'env') - .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword }); + const envStub = sinon.stub(process, 'env').value({ [`WALLET_${walletId}_PASSPHRASE`]: walletPassword }); const req = { bitgo, @@ -338,9 +337,7 @@ describe('With the handler to sign an arbitrary payload in external signing mode it('should throw error when trying to decrypt with invalid private key', async () => { const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(invalidPrv); - const envStub = sinon - .stub(process, 'env') - .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: walletPassword }); + const envStub = sinon.stub(process, 'env').value({ [`WALLET_${walletId}_PASSPHRASE`]: walletPassword }); const req = { bitgo, @@ -367,9 +364,7 @@ describe('With the handler to sign an arbitrary payload in external signing mode it('should throw error when trying to decrypt with invalid wallet passphrase key', async () => { const readFileStub = sinon.stub(fs.promises, 'readFile').resolves(validPrv); - const envStub = sinon - .stub(process, 'env') - .value({ WALLET_61f039aad587c2000745c687373e0fa9_PASSPHRASE: 'invalidPassphrase' }); + const envStub = sinon.stub(process, 'env').value({ [`WALLET_${walletId}_PASSPHRASE`]: 'invalidPassphrase' }); const req = { bitgo, diff --git a/modules/express/test/unit/typedRoutes/coinSign.ts b/modules/express/test/unit/typedRoutes/coinSign.ts index ed87e12adc..762968d02f 100644 --- a/modules/express/test/unit/typedRoutes/coinSign.ts +++ b/modules/express/test/unit/typedRoutes/coinSign.ts @@ -30,42 +30,32 @@ describe('CoinSign codec tests (External Signer Mode)', function () { const decryptedPrivKey = 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2'; const walletPassphrase = 'test_wallet_passphrase'; - // Use the existing encryptedPrivKeys.json file in the project root const path = require('path'); - const signerFilePath = path.join(__dirname, '../../../encryptedPrivKeys.json'); + const os = require('os'); + const signerFilePath = path.join(os.tmpdir(), `encryptedPrivKeys-${process.pid}-${Date.now()}.json`); let fsReadFileStub: sinon.SinonStub; let agent: ReturnType; - let originalFileContent: string; - // Mock encrypted private keys JSON content const mockSignerFileContent = JSON.stringify({ [walletId]: encryptedPrivKey, }); - // Setup the express app with signer mode before all tests before(function () { - // Save the original content of encryptedPrivKeys.json - try { - originalFileContent = fsSync.readFileSync(signerFilePath, 'utf8'); - } catch (e) { - originalFileContent = '{}'; - } - - // Temporarily write mock data to the existing file fsSync.writeFileSync(signerFilePath, mockSignerFileContent); - // Create agent with signerMode enabled for external signing agent = setupAgent({ signerMode: true, signerFileSystemPath: signerFilePath, }); }); - // Restore the original file content after all tests after(function () { - // Restore original content - fsSync.writeFileSync(signerFilePath, originalFileContent); + try { + fsSync.unlinkSync(signerFilePath); + } catch (e) { + // ignore + } }); beforeEach(function () { diff --git a/modules/express/test/unit/typedRoutes/generateShareTSS.ts b/modules/express/test/unit/typedRoutes/generateShareTSS.ts index 2fcf73c278..98e7dd29d7 100644 --- a/modules/express/test/unit/typedRoutes/generateShareTSS.ts +++ b/modules/express/test/unit/typedRoutes/generateShareTSS.ts @@ -39,40 +39,31 @@ describe('GenerateShareTSS codec tests (External Signer Mode)', function () { 'xprv9s21ZrQH143K3D8TXfvAJgHVfTEeQNW5Ys9wZtnUZkqPzFzSjbEJrWC1vZ4GnXCvR7rQL2UFX3RSuYeU9MrERm1XBvACow7c36vnz5iYyj2'; const walletPassphrase = 'test_wallet_passphrase'; const path = require('path'); - const signerFilePath = path.join(__dirname, '../../../encryptedPrivKeys.json'); + const os = require('os'); + const signerFilePath = path.join(os.tmpdir(), `encryptedPrivKeys-${process.pid}-${Date.now()}.json`); let fsReadFileStub: sinon.SinonStub; let agent: ReturnType; - let originalFileContent: string; - // Mock encrypted private keys JSON content const mockSignerFileContent = JSON.stringify({ [walletId]: encryptedPrivKey, }); - // Setup the express app with signer mode before all tests before(function () { - // Save the original content of encryptedPrivKeys.json - try { - originalFileContent = fsSync.readFileSync(signerFilePath, 'utf8'); - } catch (e) { - originalFileContent = '{}'; - } - - // Temporarily write mock data to the existing file fsSync.writeFileSync(signerFilePath, mockSignerFileContent); - // Create agent with signerMode enabled for external signing agent = setupAgent({ signerMode: true, signerFileSystemPath: signerFilePath, }); }); - // Restore the original file content after all tests after(function () { - // Restore original content - fsSync.writeFileSync(signerFilePath, originalFileContent); + try { + fsSync.unlinkSync(signerFilePath); + } catch (e) { + // ignore + } }); beforeEach(function () { diff --git a/modules/express/test/unit/typedRoutes/ofcExtSignPayload.ts b/modules/express/test/unit/typedRoutes/ofcExtSignPayload.ts index 1538d52968..3164bd9c2f 100644 --- a/modules/express/test/unit/typedRoutes/ofcExtSignPayload.ts +++ b/modules/express/test/unit/typedRoutes/ofcExtSignPayload.ts @@ -19,11 +19,11 @@ describe('OfcExtSignPayload External Signer Mode Tests', function () { const walletPassphrase = 'test_wallet_passphrase_ofc'; const path = require('path'); - const signerFilePath = path.join(__dirname, '../../../encryptedPrivKeys.json'); + const os = require('os'); + const signerFilePath = path.join(os.tmpdir(), `encryptedPrivKeys-${process.pid}-${Date.now()}.json`); let fsReadFileStub: sinon.SinonStub; let agent: ReturnType; - let originalFileContent: string; const mockSignerFileContent = JSON.stringify({ [walletId]: encryptedPrivKey, @@ -36,12 +36,6 @@ describe('OfcExtSignPayload External Signer Mode Tests', function () { }; before(function () { - try { - originalFileContent = fsSync.readFileSync(signerFilePath, 'utf8'); - } catch (e) { - originalFileContent = '{}'; - } - fsSync.writeFileSync(signerFilePath, mockSignerFileContent); agent = setupAgent({ @@ -51,7 +45,11 @@ describe('OfcExtSignPayload External Signer Mode Tests', function () { }); after(function () { - fsSync.writeFileSync(signerFilePath, originalFileContent); + try { + fsSync.unlinkSync(signerFilePath); + } catch (e) { + // ignore + } }); beforeEach(function () {