#43177 [BC-Critical] dos vulnerability in da light node via unbounded height parameter
#43177 [BC-Critical] DoS Vulnerability in DA Light Node via Unbounded Height Parameter
Submitted on Apr 3rd 2025 at 09:41:01 UTC by @Blockian for Attackathon | Movement Labs
Report ID: #43177
Report Type: Blockchain/DLT
Report severity: Critical
Target: https://github.com/immunefi-team/attackathon-movement/tree/main/protocol-units/da/movement/protocol/light-node
Impacts:
Network not being able to confirm new transactions (total network shutdown)
Description
Movement Bug Report
DoS Vulnerability in DA Light Node via Unbounded Height Parameter
Summary
The stream_read_from_height
gRPC endpoint in the DA Light Node lacks proper validation on the height
parameter. An attacker can exploit this by setting height = 0
, effectively requesting all blobs from genesis. As the network grows over time, this results in an increasingly large data request, which can overwhelm the node, leading to a denial of service (DoS) scenario.
Root Cause Analysis
The stream_read_from_height
endpoint accepts a user-controlled height
parameter and internally calls the stream_da_blobs_from_height
function:
fn stream_da_blobs_from_height(
&self,
start_height: u64,
) -> Pin<Box<dyn Future<Output = Result<DaBlobStream<C>, DaError>> + Send + '_>> {
let certificate_stream = self.stream_certificates().await?;
// ... (omitted non-relevant code)
let mut last_height = start_height;
let mut certificate_stream = certificate_stream;
while let Some(certificate) = certificate_stream.next().await {
match certificate {
Ok(Certificate::Height(height)) if height > last_height => {
let blob_stream = self
.stream_da_blobs_between_heights(last_height, height)
.await?;
tokio::pin!(blob_stream);
while let Some(blob) = blob_stream.next().await {
yield blob?;
}
// ... (omitted non-relevant code)
}
Here, the function stream_da_blobs_from_height
uses the user-supplied start_height
to stream blobs from the earliest specified height up to the latest known height (retrieved from stream_certificates
). Without validation, this can lead to excessive and unbounded data retrieval.
Impact
If an attacker sets start_height = 0
and the latest height is large, the node will:
Enter a long-running loop while attempting to stream all blobs from genesis.
Suffer from performance degradation or potentially become unresponsive.
Compromise the availability and liveness of the network by tying up resources.
Proposed Fixes
Introduce a maximum allowed range between
start_height
and the latest height when callingstream_da_blobs_between_heights
.Implement a failsafe to break out of the loop if the stream exceeds a predefined safe limit.
Proof of Concept
Proof of Concept (PoC)
Start the DA Light Node.
Set up a fake DA source populated with a large number of blobs across a high range of heights.
Send a gRPC request to the Light Node’s
stream_read_from_height
endpoint withheight = 0
.
Was this helpful?