Skip to main content

Unsafe unwrap

Description

In Rust, the unwrap method is commonly used for error handling. It retrieves the inner value of an Option or Result. If an error or None occurs, it calls panic! without a custom error message.

The usage of unwrap can lead to a panic and crash the program, which is not desired behavior in most cases, particularly in smart contracts.

Exploit Scenario

Consider the following Soroban contract:

#[contractimpl]
impl UnsafeUnwrap {
pub fn unwrap(n: u64) -> u64 {
let result = Self::non_zero_or_error(n);
result.unwrap()
}

pub fn non_zero_or_error(n: u64) -> Result<u64, Error> {
if n == 0 {
return Err(Error::CustomError);
}
Ok(n)
}
}

In this contract, the unwrap function uses the unwrap method to save the result of the non_zero_or_error function. If the function returns Err, the contract will panic and halt execution, potentially leading to malicious exploitation to disrupt the contract's operation.

The vulnerable code example can be found here.

Remediation

Instead of using unwrap, use a safer method for error handling. In this case, if the function returns Err, it will return a default value (like 0).

#[contractimpl]
impl UnsafeUnwrap {
pub fn unwrap_or_default(n: u64) -> u64 {
let result = Self::non_zero_or_error(n);
result.unwrap_or(0)
}

pub fn non_zero_or_error(n: u64) -> Result<u64, Error> {
if n == 0 {
return Err(Error::CustomError);
}
Ok(n)
}
}

The remediated code example can be found here.

References

Rust documentation: unwrap