#43229 [BC-High] There is a bug can allows malicious data to enter the DA layer and be signed by a legitimate node

Submitted on Apr 3rd 2025 at 21:35:45 UTC by @XDZIBECX for Attackathon | Movement Labs

  • Report ID: #43229

  • Report Type: Blockchain/DLT

  • Report severity: High

  • Target: https://github.com/immunefi-team/attackathon-movement/tree/main/protocol-units/da/movement/protocol/light-node

  • Impacts:

    • A bug in the respective layer 0/1/2 network code that results in unintended smart contract behavior with no concrete funds at direct risk

Description

Brief/Intro

There is a vulnerability in fn tick_publish_blobs because this function is ultimately serializes and signs Block objects and this happen using Block::try_into() without any validation on the block’s content, or structure, or logical consistency, and the try_into() implementation simply is uses bcs::to_bytes(&block)?, mean it's blindly encodes any block — and this can include a malformed, fake, or malicious ones — into a byte array, which is then signed and submitted to the DA layer as an authentic, trusted blob, this is a problem because this behavior is not safe and is breaks the assumption that all published blocks are verified and canonical, because without verifying that the block.id matches its contents, that the parent block exists, that the timestamp is valid, and that transactions are bounded, unique, and properly ordered, the system effectively can allows arbitrary data to be signed and committed to history. This is not safe: it creates a trust-breaking path where a fake blocks can be submitted as real, see vulnerability details to see where this problem came from .

Vulnerability Details

here on the tick_publish_blobs() – there is no validation before submission --> https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/protocol-units/da/movement/protocol/light-node/src/sequencer.rs#L235 :

self.submit_blocks(blocks).await?;

This line blindly forwards a list of blocks to submit_blocks() and this without performing any structural or semantic validation on the blocks and is show that there is not check on : block.id matching its contents block.parent pointing to a known parent transactions being unique, bounded, or properly ordered

  • here on submit_blocks() this is the vulnerable block conversion -->https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/protocol-units/da/movement/protocol/light-node/src/sequencer.rs#L167

This line is calls .try_into() on the Block, and is assuming it is well-formed but the implementation of .try_into() does not perform validation — it only serializes

  • and here https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/protocol-units/da/movement/protocol/util/src/blob/ir/data.rs#L79 the try_into() implementation also does not verify that if the block.id matches a hash of its content or if the parent block is valid or known or if the transaction list is not malformed or oversized

  • and here https://github.com/immunefi-team/attackathon-movement/blob/a2790c6ac17b7cf02a69aea172c2b38d2be8ce00/protocol-units/da/movement/protocol/light-node/src/sequencer.rs#L169 the signed blob is submitted to the Celestia DA layer and It's becomes part of the canonical data availability history even though it was never validated this is a risk and need to bee fixed it's must add a validate_block() function before calling .try_into() or .try_to_sign()

attack path :

  • This Bug is can Allows Malicious or Malformed Data to Enter the DA Layer and Be Signed by a Legitimate Node so let's say an attacker Sends a Malicious Input via batch_write() as :

so If the LightNode is not configured with a prevalidator, the node is blindly accepts any transaction blob and pushes it into the internal transaction pool (memseq).

  • the transactions Enter memseq, are automatically turned Into a Block because Inside tick_build_blocks() here :

memseq is responsible for Receiving transactions and Aggregating them into a block and Returning that Block to the LightNode runtime But there's no validation here. and It assumes transactions are clean and that blocks are well-formed which may not be true for attacker-controlled input.

  • And the Block Is Submitted Without any Validation or Verification because Inside tick_publish_blobs() on this line :

and then inside submit_blocks() on this line :

The block.try_into() function is implemented as:

So, whatever gets passed into block, whether it's A block with a fake or unknown parent or Invalid or unordered transactions or a block with the wrong block.id (not matching its contents) …it still gets serialized, signed, and submitted to Celestia, indistinguishable from a real block.

  • an attacker can exploit this by sends a validly formatted but are logically incorrect blob to batch_write() and block Contains a transaction that manipulates block internals ( includes malicious tx data, or weird timestamps) so the node accepts the blob because prevalidator == None, then the blob enters memseq, and is added to the next Block That block is : - Contains an invalid parent (e.g., 0xdead...) - An inconsistent id (doesn't match the hash of the contents) -10,000 spam transactions (DoS) so Node serializes it via .try_into() without checking anything and then Signs it and submits to Celestia as result a fake block becomes permanent history, and signed by a real node

Impact Details

This bug is can allows malicious or malformed data to enter the DA layer and be signed by a legitimate node, and this is making it indistinguishable from valid, well-formed blocks. While no direct user funds are at risk from this bug alone,

The vulnerability is in core layer 1 protocol code and It breaks data integrity and DA trust assumptions But there is no fund at risk

References

Proof of Concept

Proof of Concept

Was this helpful?