VYPR
High severityNVD Advisory· Published Sep 5, 2024· Updated Sep 5, 2024

Memory leak when calling a canister method via `ic_cdk::call`

CVE-2024-7884

Description

When a canister method is called via ic_cdk::call* , a new Future CallFuture is created and can be awaited by the caller to get the execution result. Internally, the state of the Future is tracked and stored in a struct called CallFutureState. A bug in the polling implementation of the CallFuture allows multiple references to be held for this internal state and not all references were dropped before the Future is resolved. Since we have unaccounted references held, a copy of the internal state ended up being persisted in the canister's heap and thus causing a memory leak. Impact Canisters built in Rust with ic_cdk and ic_cdk_timers are affected. If these canisters call a canister method, use timers or heartbeat, they will likely leak a small amount of memory on every such operation. In the worst case, this could lead to heap memory exhaustion triggered by an attacker. Motoko based canisters are not affected by the bug. PatchesThe patch has been backported to all minor versions between >= 0.8.0, <= 0.15.0. The patched versions available are 0.8.2, 0.9.3, 0.10.1, 0.11.6, 0.12.2, 0.13.5, 0.14.1, 0.15.1 and their previous versions have been yanked. WorkaroundsThere are no known workarounds at the moment. Developers are recommended to upgrade their canister as soon as possible to the latest available patched version of ic_cdk to avoid running out of Wasm heap memory. Upgrading the canisters (without updating ic_cdk) also frees the leaked memory but it's only a temporary solution.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

A memory leak in ic_cdk's CallFuture polling logic can lead to heap exhaustion in Rust-based Internet Computer canisters, patched in multiple versions.

Vulnerability

Details

A bug in the polling implementation of the CallFuture type in the ic_cdk Rust library causes a memory leak when canister methods are called via ic_cdk::call*. Internally, the future's state is tracked in a CallFutureState struct. Due to improper reference counting, not all references are dropped before the future resolves, leaving a copy of the state persisted in the canister's heap [1][2].

Attack

Vector

Any canister built with Rust and using ic_cdk or ic_cdk_timers is affected. An attacker can trigger the leak by repeatedly calling canister methods, using timers, or relying on heartbeat operations. No authentication or special privileges are required; the attack is network-based. Over time, the accumulated leaked memory can exhaust the canister's Wasm heap [2][3].

Impact

Successful exploitation leads to heap memory exhaustion, resulting in a denial of service. The canister may become unresponsive or fail to process further requests. Motoko-based canisters are not affected [2].

Mitigation

Patches have been backported to all minor versions between 0.8.0 and 0.15.0. The patched versions are 0.8.2, 0.9.3, 0.10.1, 0.11.6, 0.12.2, 0.13.5, 0.14.1, and 0.15.1; previous versions have been yanked. No workarounds exist; developers should upgrade immediately. Temporarily upgrading the canister without updating ic_cdk frees leaked memory but is not a permanent fix [2][3].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
ic_cdkcrates.io
>= 0.8.0, < 0.8.20.8.2
ic_cdkcrates.io
>= 0.9.0, < 0.9.30.9.3
ic_cdkcrates.io
>= 0.10.0, < 0.10.10.10.1
ic_cdkcrates.io
>= 0.11.0, < 0.11.60.11.6
ic_cdkcrates.io
>= 0.12.0, < 0.12.20.12.2
ic_cdkcrates.io
>= 0.13.0, < 0.13.50.13.5
ic_cdkcrates.io
>= 0.14.0, < 0.14.10.14.1
ic_cdkcrates.io
>= 0.15.0, < 0.15.10.15.1

Affected products

3

Patches

1
bd17d57a7b8c

fix: Fix memory leak in CallFuture (#509)

https://github.com/dfinity/cdk-rsAdam SpoffordAug 16, 2024via ghsa
1 file changed · +1 1
  • src/ic-cdk/src/api/call.rs+1 1 modified
    @@ -74,7 +74,6 @@ impl<T: AsRef<[u8]>> Future for CallFuture<T> {
     
         fn poll(self: Pin<&mut Self>, context: &mut Context<'_>) -> Poll<Self::Output> {
             let self_ref = Pin::into_inner(self);
    -        let state_ptr = Weak::into_raw(Arc::downgrade(&self_ref.state));
             let mut state = self_ref.state.write().unwrap();
     
             if let Some(result) = state.result.take() {
    @@ -85,6 +84,7 @@ impl<T: AsRef<[u8]>> Future for CallFuture<T> {
                     let method = &state.method;
                     let args = state.arg.as_ref();
                     let payment = state.payment;
    +                let state_ptr = Weak::into_raw(Arc::downgrade(&self_ref.state));
                     // SAFETY:
                     // `callee`, being &[u8], is a readable sequence of bytes and therefore can be passed to ic0.call_new.
                     // `method`, being &str, is a readable sequence of bytes and therefore can be passed to ic0.call_new.
    

Vulnerability mechanics

Root cause

"Improper polling implementation in CallFuture causes unaccounted references to persist in the canister's heap, leading to a memory leak."

Attack vector

An attacker can trigger this vulnerability by repeatedly invoking canister methods that utilize `ic_cdk::call*`, timers, or heartbeat functionality. Each operation causes a small amount of memory to leak due to the improper handling of `CallFutureState` references. Over time, this accumulation can lead to heap memory exhaustion, potentially causing a denial-of-service condition for the affected canister [patch_id=27826].

Affected code

The memory leak occurs within the `poll` function of the `CallFuture` struct located in `src/ic-cdk/src/api/call.rs`. The implementation incorrectly managed references to the internal `CallFutureState` by creating a `Weak` reference before the future was resolved, preventing proper cleanup [patch_id=27826].

What the fix does

The patch modifies `src/ic-cdk/src/api/call.rs` to move the creation of the `state_ptr` (a `Weak` reference to the internal state) inside the block that executes only when the future is not yet resolved. By delaying the creation of this reference until it is actually needed for the call, the patch ensures that unnecessary references are not held, allowing the internal state to be properly dropped and preventing the memory leak [patch_id=27826].

Preconditions

  • configThe canister must be built in Rust using affected versions of ic_cdk (>= 0.8.0, <= 0.15.0).
  • inputThe canister must perform operations that use ic_cdk::call*, timers, or heartbeat.

Generated on May 17, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

9

News mentions

0

No linked articles in our index yet.