From 8eb3fbc86ee99bfcc4a5f0ace91afda42fc068e3 Mon Sep 17 00:00:00 2001 From: mononaut Date: Thu, 28 May 2026 05:23:08 +0000 Subject: [PATCH 1/2] add missing validation to transaction-times route --- backend/src/api/bitcoin/bitcoin.routes.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index 9d9b5f262..b608615a8 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -28,6 +28,7 @@ const TXID_REGEX = /^[a-f0-9]{64}$/i; const BLOCK_HASH_REGEX = /^[a-f0-9]{64}$/i; const ADDRESS_REGEX = /^[a-z0-9]{2,120}$/i; const SCRIPT_HASH_REGEX = /^([a-f0-9]{2})+$/i; +const MAX_TRANSACTION_TIMES = 100; class BitcoinRoutes { public initRoutes(app: Application) { @@ -147,8 +148,15 @@ class BitcoinRoutes { handleError(req, res, 500, 'invalid txId format'); return; } + + const requestedTxIds = Object.values(req.query.txId); + if (requestedTxIds.length > MAX_TRANSACTION_TIMES) { + handleError(req, res, 400, 'Too many txids requested'); + return; + } + const txIds: string[] = []; - for (const txid of Object.values(req.query.txId)) { + for (const txid of requestedTxIds) { if (typeof txid === 'string' && TXID_REGEX.test(txid)) { txIds.push(txid); } From 901a117e7c57a6f8b24c216fa399bfe15f817fed Mon Sep 17 00:00:00 2001 From: mononaut Date: Thu, 28 May 2026 05:27:43 +0000 Subject: [PATCH 2/2] fix incorrect http status codes --- backend/src/api/bitcoin/bitcoin.routes.ts | 56 +++++++++++------------ 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index b608615a8..4b8aecab8 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -145,7 +145,7 @@ class BitcoinRoutes { private getTransactionTimes(req: Request, res: Response) { if (!req.query.txId || typeof req.query.txId !== 'object') { - handleError(req, res, 500, 'invalid txId format'); + handleError(req, res, 400, 'invalid txId format'); return; } @@ -169,7 +169,7 @@ class BitcoinRoutes { private async $getBatchedOutspends(req: Request, res: Response): Promise { const txids_csv = req.query.txids; if (!txids_csv || typeof txids_csv !== 'string') { - handleError(req, res, 500, 'Invalid txids format'); + handleError(req, res, 400, 'Invalid txids format'); return; } const txids = txids_csv.split(','); @@ -192,7 +192,7 @@ class BitcoinRoutes { private async $getCpfpInfo(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } @@ -254,7 +254,7 @@ class BitcoinRoutes { private async getTransaction(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -273,7 +273,7 @@ class BitcoinRoutes { private async getRawTransaction(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -361,7 +361,7 @@ class BitcoinRoutes { private async getTransactionStatus(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -380,7 +380,7 @@ class BitcoinRoutes { private async getStrippedBlockTransactions(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -394,11 +394,11 @@ class BitcoinRoutes { private async getStrippedBlockTransaction(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } if (!TXID_REGEX.test(req.params.txid)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -416,7 +416,7 @@ class BitcoinRoutes { private async getBlock(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -442,7 +442,7 @@ class BitcoinRoutes { private async getBlockHeader(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -456,7 +456,7 @@ class BitcoinRoutes { private async getBlockAuditSummary(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -475,11 +475,11 @@ class BitcoinRoutes { private async $getBlockTxAuditSummary(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } if (!TXID_REGEX.test(req.params.txid)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -629,7 +629,7 @@ class BitcoinRoutes { private async getBlockTransactions(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -671,7 +671,7 @@ class BitcoinRoutes { return; } if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } @@ -697,7 +697,7 @@ class BitcoinRoutes { return; } if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } @@ -727,7 +727,7 @@ class BitcoinRoutes { return; } if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } @@ -760,7 +760,7 @@ class BitcoinRoutes { return; } if (!SCRIPT_HASH_REGEX.test(req.params.scripthash)) { - handleError(req, res, 501, `Invalid scripthash`); + handleError(req, res, 400, `Invalid scripthash`); return; } @@ -784,7 +784,7 @@ class BitcoinRoutes { return; } if (!SCRIPT_HASH_REGEX.test(req.params.scripthash)) { - handleError(req, res, 501, `Invalid scripthash`); + handleError(req, res, 400, `Invalid scripthash`); return; } @@ -812,7 +812,7 @@ class BitcoinRoutes { return; } if (!SCRIPT_HASH_REGEX.test(req.params.scripthash)) { - handleError(req, res, 501, `Invalid scripthash`); + handleError(req, res, 400, `Invalid scripthash`); return; } @@ -945,7 +945,7 @@ class BitcoinRoutes { private async getRawBlock(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -959,7 +959,7 @@ class BitcoinRoutes { private async getTxIdsForBlock(req: Request, res: Response) { if (!BLOCK_HASH_REGEX.test(req.params.hash)) { - handleError(req, res, 501, `Invalid block hash`); + handleError(req, res, 400, `Invalid block hash`); return; } try { @@ -972,7 +972,7 @@ class BitcoinRoutes { private async validateAddress(req: Request, res: Response) { if (!ADDRESS_REGEX.test(req.params.address)) { - handleError(req, res, 501, `Invalid address`); + handleError(req, res, 400, `Invalid address`); return; } try { @@ -985,7 +985,7 @@ class BitcoinRoutes { private async getRbfHistory(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -1020,7 +1020,7 @@ class BitcoinRoutes { private async getCachedTx(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -1037,7 +1037,7 @@ class BitcoinRoutes { private async getTransactionOutspends(req: Request, res: Response) { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try { @@ -1050,7 +1050,7 @@ class BitcoinRoutes { private async getTransactionMerkleProof(req: Request, res: Response): Promise { if (!TXID_REGEX.test(req.params.txId)) { - handleError(req, res, 501, `Invalid transaction ID`); + handleError(req, res, 400, `Invalid transaction ID`); return; } try {