Delegate call bug in ink!
Introduction
ink! is a programming language for smart contracts. It can be used in parachains built on Substrate. There was a bug in the CallBuilder::delegate()
method and ink_env::invoke_contract_delegate()
function which returns unexpected values.
When using the function build_call::<>().delegate(target)
we observe that:
- The storage cell key is calculated correctly.
- The storage value is being decoded incorrectly.
This can be traced to the `LangError` implementation that changed in #1450 and was introduced in v4.0.0.
We assess the severity of the vulnerability as low.
CVE reference CVE-2023-34449
Affected versions
The issue affects versions v4.0.0, v4.0.1, v4.1.0. v4.2.0.
Minimal Error Example
// First contract, this will be performing a delegate call to the `Callee`. #[ink(storage)] pub struct Caller { value: u128, } #[ink(message)] pub fn get_value(&self, callee_code_hash: Hash) -> u128 { let result = build_call::<DefaultEnvironment>() .delegate(callee_code_hash) .exec_input(ExecutionInput::new(Selector::new(ink::selector_bytes!( "get_value" )))) .returns::<u128>() .invoke(); result } // Different contract, using this code hash for the delegate call. #[ink(storage)] pub struct Callee { value: u128, } #[ink(message)] pub fn get_value(&self) -> u128 { self.value }
The delegated contract in this example only returns the value.
Expected: 1
Received: 256
Every time a number is returned, it is equal to the expected value times 256 (1 byte).
This is a minimal representation of the error in the ink! documentation:
Cross-Contract Calling | ink! documentation
Testing on Different Types
We tested the use of delegate calls on different ink! types obtaining the following results.
Uint
We observe that the storage value returned is shifted by one byte (eight bit shifts left wise). The expected value can be obtained by dividing by 256.
String
An empty value is returned.
Lazy
The key is not being resolved consistently (it is dependent on the contract names, addresses and variables). If the value is fixed through a manual key, the returned value maintains the same errors as observed in ‘uint’.
Survey of Repos Using Delegate
We found several repositories on GitHub that could be potentially affected by this malfunctionality.
The vendor, Parity, reported it did not find deployed contracts on Shiden, Astar or Aleph Zero affected by this vulnerability
Fix
We informed Parity about the bug, and it was solved in #1808. If you are using one of the affected versions (v4.0.0, v4.0.1, v4.1.0. v4.2.0), please update to v4.2.1.
References
- Ink! https://use.ink/
- Fix https://github.com/paritytech/ink/pull/1808
- Fixed release: https://github.com/paritytech/ink/releases/tag/v4.2.1
- Parity’s Advisory: https://github.com/paritytech/ink/security/advisories/GHSA-853p-5678-hv8f
- This advisory: https://blog.coinfabrik.com/delegate-call-error-decoding-langerror/
- CVE = CVE-2023-34449
Credits
This issue was found by Facundo Lerena with the assistance of Agustín Losiggio, Arturo Beccar-Varela and Agustín Aon, all members of CoinFabrik.
Disclosure timeline
This timeline is not exhaustive and only lists events that we deemed relevant to the disclosure process.
- 2023-06-13 CoinFabrik sent the vulnerability report to Parity.
- 2023-06-13 Parity acknowledges the report and sends a fix solving the issue.
- 2023-06-14 CoinFabrik validates the fix.
- 2023-06-14 Parity pushes the fixed version and releases an advisory.
- 2023-06-14 CoinFabrik releases this advisory.
About CoinFabrik
We – CoinFabrik – are a research and development company specialized in Web3, with a strong background in cybersecurity. Founded in 2014, we have worked on over 180 blockchain-related projects, EVM based and also for Solana, Algorand, and Polkadot. Beyond development, we offer security audits through a dedicated in-house team of senior cybersecurity professionals, currently working on code in Substrate, Solidity, Clarity, Rust, and TEAL.
Our team has an academic background in computer science and mathematics, with work experience focused on cybersecurity and software development, including academic publications, patents turned into products, and conference presentations. Furthermore, we have an ongoing collaboration on knowledge transfer and open-source projects with the University of Buenos Aires.