The set_code function in the vault contract allows upgrading the contract code. However, it only checks if the caller is the role_owner without any additional security measures. This could lead to unauthorized access if the role_owner account is compromised.
Attack Scenario
An attacker who gains control of the role_owner account can call the set_code function to upgrade the contract to malicious code, potentially stealing all funds.
Attachments
Proof of Concept (PoC) File
/// Upgrade the contract by the ink env set_code_hash function
Github username: @neuraldevx Twitter username: realjakechris Submission hash (on-chain): 0x1fa9adc25867736a3600b2d7a415c4c234d03bfefd5ffaabb166aed2038c190f Severity: high
Description: Description
The set_code function in the vault contract allows upgrading the contract code. However, it only checks if the caller is the role_owner without any additional security measures. This could lead to unauthorized access if the role_owner account is compromised.
Attack Scenario
An attacker who gains control of the role_owner account can call the set_code function to upgrade the contract to malicious code, potentially stealing all funds.
Attachments
/// Upgrade the contract by the ink env set_code_hash function
/// Caller must have the owner role (
role_owner
)/// See ink documentation for details https://paritytech.github.io/ink/ink_env/fn.set_code_hash.html
[ink(message)]
pub fn set_code(&mut self, code_hash: [u8; 32]) -> Result<(), VaultError> { let caller = Self::env().caller();
}
Revised Code File (Optional)
/// Upgrade the contract by the ink env set_code_hash function /// /// Caller must have the owner role (
role_owner
) /// See ink documentation for details https://paritytech.github.io/ink/ink_env/fn.set_code_hash.html[ink(message)]
pub fn set_code(&mut self, code_hash: [u8; 32]) -> Result<(), VaultError> { let caller = Self::env().caller();
if caller != self.data.role_owner { return Err(VaultError::InvalidPermissions); }
// Implementing a time-lock mechanism if Self::env().block_timestamp() < self.data.code_update_time + TIME_LOCK_PERIOD { return Err(VaultError::TimeLockActive); }
ink::env::set_code_hash(&code_hash)?;
// Update the time of the last code update self.data.code_update_time = Self::env().block_timestamp();
Ok(()) }