Delegatecall to an untrusted callee
delegatecall runs someone else’s code against your storage and your balance.
What it is
delegatecall executes the target’s code in your contract’s context: your storage slots, your balance, your address as msg.sender downstream. If a caller can influence which address is delegated to, they choose the code that runs as you.
Why it matters
Total compromise. The delegate can overwrite any storage slot — including the owner — and move the entire balance. Proxy patterns add a second failure mode: if the proxy and implementation disagree about storage layout, an upgrade silently corrupts state.
The vulnerable pattern
The caller picks the code that runs with your storage.
function execute(address target, bytes calldata data) external {
(bool ok, ) = target.delegatecall(data);
require(ok);
}How to fix it
- Never delegatecall to an address a caller can supply. Use an immutable target, or an allowlist that only a privileged role can change.
- For proxies, use a maintained implementation and keep storage layouts append-only across upgrades.
- Make sure the implementation contract cannot be initialised directly by an attacker.
How it is detected
Every audit on EVM Smart Audit checks for SWC-112 and reports it as passed or flagged in the standards coverage grid — so the report tells you it was checked even when nothing was found. See the detector suite for what else runs alongside it, or the full database for the other 21 checks.
Check your contract for delegatecall to an untrusted callee
The engine runs this check and 21 others on every audit, and shows what passed as well as what failed.