# #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**](https://immunefi.com/audit-competition/movement-labs-attackathon)

* **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:

```rs
	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 calling `stream_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)

1. Start the DA Light Node.
2. Set up a fake DA source populated with a large number of blobs across a high range of heights.
3. Send a gRPC request to the Light Node’s `stream_read_from_height` endpoint with `height = 0`.
