From 42e879e768000b4e64d8f8293444dbbead40832e Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Mon, 10 Aug 2026 15:16:20 -0700 Subject: [PATCH] Add stricter validation on block_info response. --- src/lib/rpc/block_info.ts | 75 ++++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/src/lib/rpc/block_info.ts b/src/lib/rpc/block_info.ts index fdbdc67..35e064e 100644 --- a/src/lib/rpc/block_info.ts +++ b/src/lib/rpc/block_info.ts @@ -38,18 +38,22 @@ export type BlockInfoResponse = { export function block_info (body: unknown): BlockInfoResponse { if (body != null && typeof body === 'object') { - if ('amount' in body && typeof body.amount === 'string' - && 'balance' in body && typeof body.balance === 'string' - && 'block_account' in body && typeof body.block_account === 'string' - && 'confirmed' in body && typeof body.confirmed === 'string' - && 'height' in body && typeof body.height === 'string' - && 'linked_account' in body && typeof body.linked_account === 'string' - && 'local_timestamp' in body && typeof body.local_timestamp === 'string' + if ('error' in body && typeof body.error === 'string') { + throw new RpcError(body.error) + } + + if ('amount' in body && typeof body.amount === 'string' && /^\d+$/.test(body.amount) + && 'balance' in body && typeof body.balance === 'string' && /^\d+$/.test(body.balance) + && 'block_account' in body && Account.isValid(body.block_account) + && 'confirmed' in body && (body.confirmed === 'true' || body.confirmed === 'false') + && 'height' in body && typeof body.height === 'string' && /^\d+$/.test(body.height) + && 'linked_account' in body && (body.linked_account === '0' || Account.isValid(body.linked_account)) + && 'local_timestamp' in body && typeof body.local_timestamp === 'string' && /^\d+$/.test(body.local_timestamp) && 'subtype' in body && (body.subtype === 'change' || body.subtype === 'epoch' || body.subtype === 'open' || body.subtype === 'receive' || body.subtype === 'send') - && 'successor' in body && typeof body.successor === 'string' + && 'successor' in body && hex.is(body.successor, 64) && 'contents' in body && body.contents != null && typeof body.contents === 'object' - && 'account' in body.contents && typeof body.contents.account === 'string' - && 'balance' in body.contents && typeof body.contents.balance === 'string' + && 'account' in body.contents && Account.isValid(body.contents.account) + && 'balance' in body.contents && typeof body.contents.balance === 'string' && /^\d+$/.test(body.contents.balance) && 'link' in body.contents && hex.is(body.contents.link, 64) && 'link_as_account' in body.contents && Account.isValid(body.contents.link_as_account) && 'previous' in body.contents && hex.is(body.contents.previous, 64) @@ -58,32 +62,31 @@ export function block_info (body: unknown): BlockInfoResponse { && 'type' in body.contents && body.contents.type === 'state' && 'work' in body.contents && typeof body.contents.work === 'string' ) { - return { - contents: { - account: body.contents.account, - balance: body.contents.balance, - link: body.contents.link, - link_as_account: body.contents.link_as_account, - previous: body.contents.previous, - representative: body.contents.representative, - signature: body.contents.signature, - type: body.contents.type, - work: body.contents.work, - }, - amount: body.amount, - balance: body.balance, - block_account: body.block_account, - confirmed: body.confirmed, - height: body.height, - linked_account: body.linked_account, - local_timestamp: body.local_timestamp, - subtype: body.subtype, - successor: body.successor, - } - } - if ('error' in body && typeof body.error === 'string') { - throw new RpcError(body.error) + const response: BlockInfoResponse = Object.create(null) + response.amount = body.amount + response.balance = body.balance + response.block_account = body.block_account + response.confirmed = body.confirmed + response.height = body.height + response.linked_account = body.linked_account + response.local_timestamp = body.local_timestamp + response.subtype = body.subtype + response.successor = body.successor + + const contents: BlockInfoContents = Object.create(null) + contents.account = body.contents.account + contents.balance = body.contents.balance + contents.link = body.contents.link + contents.link_as_account = body.contents.link_as_account + contents.previous = body.contents.previous + contents.representative = body.contents.representative + contents.signature = body.contents.signature + contents.type = body.contents.type + contents.work = body.contents.work + response.contents = contents + + return response } } - throw new RpcError('Invalid block_info response') + throw new RpcError('Invalid block_info response', { cause: body }) } -- 2.52.0