Skip to main content

Unprotected update current contract wasm

Description​

It warns you if update_current_contract_wasm() function is called without a previous check of the address of the caller.

Why is this bad?​

If users are allowed to call update_current_contract_wasm(), they can intentionally modify the contract behaviour, leading to the loss of all associated data/tokens and functionalities given by this contract or by others that depend on it.

Issue example​

Consider the following Soroban contract:


#[contractimpl]
impl UpgradeableContract {
pub fn init(e: Env, admin: Address) {
e.storage().instance().set(&DataKey::Admin, &admin);
}

pub fn version() -> u32 {
1
}

pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) {
e.deployer().update_current_contract_wasm(new_wasm_hash);
}
}

This contract allows upgrades through the update_current_contract_wasm function. If just anyone can call this function, they could modify the contract behaviour.

The code example can be found here.

Remediated example​

To prevent this, the function should be restricted to administrators or authorized users only.


#[contractimpl]
impl UpgradeableContract {
pub fn init(e: Env, admin: Address) {
e.storage().instance().set(&DataKey::Admin, &admin);
}

pub fn version() -> u32 {
1
}

pub fn upgrade(e: Env, new_wasm_hash: BytesN<32>) {
let admin: Address = e.storage().instance().get(&DataKey::Admin).unwrap();
admin.require_auth();

e.deployer().update_current_contract_wasm(new_wasm_hash);
}
}

The remediated code example can be found here.

How is it detected?​

It warns you if update_current_contract_wasm() function is called without a previous check of the address of the caller.