#43333 [BC-Critical] Missing Depths Checks in Cached TypeLayout leads to Network Divergence

Submitted on Apr 4th 2025 at 17:06:23 UTC by @dustincha for Attackathon | Movement Labs

  • Report ID: #43333

  • Report Type: Blockchain/DLT

  • Report severity: Critical

  • Target: https://github.com/immunefi-team/attackathon-movement-aptos-core/tree/main

  • Impacts:

    • Unintended chain split (network partition)

Description

Brief/Intro

During an in-depth review of Movement VM's type layout construction, I observed a critical issue relating to the caching of constructed type layouts. Initially, while analyzing type construction and the associated depth checks, I noticed these checks are only performed during the initial construction of a type layout and are not repeated when fetching layouts from cache. I looked into potential DOS abusing this behavior, but actually found this can lead to execution inconsistencies give the order of execution and what is already in the cache.

Vulnerability Details

When building type layouts (https://github.com/immunefi-team/attackathon-movement-aptos-core/blame/627b4f9e0b63c33746fa5dae6cd672cbee3d8631/third_party/move/move-vm/runtime/src/loader/mod.rs#L1794-L1801C8), a maximum depth check of 128 is enforced. However, the same check is not enforced within struct_name_to_type_layout when fetching types from the cache (https://github.com/immunefi-team/attackathon-movement-aptos-core/blame/627b4f9e0b63c33746fa5dae6cd672cbee3d8631/third_party/move/move-vm/runtime/src/loader/mod.rs#L1677-L1687). This means that if part of the recursive structure has already been built and cached, the type could be successfully created even if it exceeds the intended depth limit.

Consider two threads, T1 and T2:

  • Thread T1 executes create_v3 just before Thread T2 executes create_v128. When Thread T2 constructs V128, it reaches just before the maximum depth, finds V3 already cached, uses it directly, and bypasses further depth checks, causing the transaction to succeed.

  • Conversely, if Thread T2 executes first, create_v128 will fail, as it exceeds the maximum allowed depth.

This scenario clearly demonstrates a potential execution divergence issue.

Impact Details

The network will diverge and split depending on which transaction gets executed first.

Proof of Concept

Proof of Concept

I originally intended to provide a complete E2E PoC, but encountered some issues running both the Movement CLI and Aptos CLI in the NIX environment. Although I was actively working on resolving these issues, unfortunately, the deadline is approaching quickly, and I'd prefer not to risk missing it.

Run the test with: DOT_MOVEMENT_PATH=../../../.movement cargo test test_cache_typelayout -- --nocapture from networks/movement/movement-client/.

Was this helpful?