# Wallet Protocol Draft ## Implementation contract can be destroyed by anyone **Severity**: High **Context**: [`Implementation.sol#L17`](https://github.com/spearbit-audits/writing-exercise/blob/develop/contracts/Implementation.sol#L17) - delegatecallContract can be called by anyone and call delegate call to any arbitrary address. - If delegatecallContract is called directly rather than from proxy, and it delegates to a contract and that delegatee contract executes `SELFDESTRUCT` then the logic of proxy is erased and becomes `0x` leaving it unusable for all of the proxies. **POC** ```solidity // SPDX-License-Identifier: MIT pragma solidity 0.8.10; contract Malicious { function kill() external payable { selfdestruct(payable(address(0))); } } ``` If `Implementation.delegatecallContract` is called directly (without using proxy) and delegates call to`Malicious`, then `Implementation` is destroyed **Recommendations** ```diff diff --git a/contracts/Implementation.sol b/contracts/Implementation.sol index a7ab071..3bd3329 100644 --- a/contracts/Implementation.sol +++ b/contracts/Implementation.sol @@ -8,6 +8,12 @@ pragma solidity 0.8.10; /// Only deployed once and the implementation is reused by all proxy contracts. contract Implementation { + address immutable self; + + constructor() { + self = address(this); + } + function callContract(address a, bytes calldata _calldata) payable external returns (bytes memory) { (bool success , bytes memory ret) = a.call{value: msg.value}(_calldata); require(success); @@ -15,6 +21,7 @@ contract Implementation { } function delegatecallContract(address a, bytes calldata _calldata) payable external returns (bytes memory) { + require(address(this) != self); (bool success, bytes memory ret) = a.delegatecall(_calldata); require(success); return ret; ``` - when the `Implementation` contract is deployed, register its real address in variable and on each delegatecall, compare execution context address with a real address, it should not be same to prevent it being called directly.