From c63414d7c2d4048790b5bc1fdbf7c4dea535e60b Mon Sep 17 00:00:00 2001 From: Francis Li Date: Mon, 5 Oct 2026 19:02:15 +0000 Subject: [PATCH] fix(anvil): reject malformed Beacon blob versioned_hashes filters Invalid hashes were dropped, so a bad filter returned more blobs than requested or every blob in the block. Amp-Thread-ID: https://ampcode.com/threads/T-01a10d69-00b6-7378-855f-af2b1a148692 Co-authored-by: Amp --- crates/anvil/src/server/beacon/handlers.rs | 17 ++++++++++++----- crates/anvil/tests/it/beacon_api.rs | 11 +++++++++++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/crates/anvil/src/server/beacon/handlers.rs b/crates/anvil/src/server/beacon/handlers.rs index 15876a8bf..0f8e466c5 100644 --- a/crates/anvil/src/server/beacon/handlers.rs +++ b/crates/anvil/src/server/beacon/handlers.rs @@ -1,4 +1,7 @@ -use super::{error::BeaconError, utils::must_be_ssz}; +use super::{ + error::{BeaconError, BeaconErrorCode}, + utils::must_be_ssz, +}; use crate::eth::EthApi; use alloy_eips::BlockId; use alloy_primitives::{B256, aliases::B32}; @@ -45,13 +48,17 @@ pub async fn handle_get_blobs( // Parse indices from query parameters // Supports both comma-separated (?indices=1,2,3) and repeated parameters (?indices=1&indices=2) - let versioned_hashes: Vec = versioned_hashes + let Ok(versioned_hashes) = versioned_hashes .get("versioned_hashes") - .map(|s| s.split(',').filter_map(|hash| B256::from_str(hash.trim()).ok()).collect()) - .unwrap_or_default(); + .map(|s| s.split(',').map(|hash| B256::from_str(hash.trim())).collect()) + .transpose() + else { + return BeaconError::new(BeaconErrorCode::BadRequest, "Invalid versioned_hashes") + .into_response(); + }; // Get the blob sidecars using existing EthApi logic - match api.anvil_get_blobs_by_block_id(block_id, versioned_hashes) { + match api.anvil_get_blobs_by_block_id(block_id, versioned_hashes.unwrap_or_default()) { Ok(Some(blobs)) => { if must_be_ssz(&headers) { blobs.as_ssz_bytes().into_response() diff --git a/crates/anvil/tests/it/beacon_api.rs b/crates/anvil/tests/it/beacon_api.rs index 9039acdc2..adaecf26e 100644 --- a/crates/anvil/tests/it/beacon_api.rs +++ b/crates/anvil/tests/it/beacon_api.rs @@ -218,6 +218,17 @@ async fn test_beacon_api_get_blobs() { "Expected 0 blobs when filtering by non-existent versioned_hash" ); + // Ignoring invalid filters would broaden the request + let partly_invalid = format!("{},0xzz", actual_versioned_hashes[0]); + for filter in ["0x1234", "not-a-hash", "", partly_invalid.as_str()] { + let url = format!( + "{}/eth/v1/beacon/blobs/{block_number}?versioned_hashes={filter}", + handle.http_endpoint() + ); + let response = client.get(&url).send().await.unwrap(); + assert_eq!(response.status(), reqwest::StatusCode::BAD_REQUEST, "filter {filter:?}"); + } + // Test with special block identifiers let test_ids = vec!["latest", "finalized", "safe", "earliest"]; for block_id in test_ids {