This agent detects when an attacker could trigger a selfdestruct of a UUPS implementation contract, leaving a proxy contract permanently broken. The agent is separated into three threads:
- First thread detects contracts that are not initialized.
- Second thread detects the main exploit and tries to anticipate it - if new contract logic exists but selfdestruct method is reachable in the byte-code - this thread will provide the alert too.
- Third thread detects when a contract is initialized by TransferOwnership event where the previous owner was 0x0000000000000000000000000000000000000000
For a detailed description of the issue refer to the post-mortem.
- Ethereum
-
UUPS-EXPLOIT
- Fired when there is
Upgraded(address)
event in the log and new implementation address returns an empty byte-code - Severity is always set to
Critical
- Type is always set to
Exploit
- Metadata:
tx_hash
- hash of the transactionnew_implementation
- address of the new implementationattacker_address
- sender of the transaction
- Fired when there is
-
LOGIC-NOT-INIT
- Fired when the delegatecall target address has an owner with an address 0x0000000000000000000000000000000000000000
- Severity is always set to
High
- Type is always set to
Unknown
- Metadata:
tx_hash
- hash of the transactioncontract
- address of the implementationproxy
- address of the proxy
-
LOGIC-CAN-SELFDESTRUCT
- Fired when selfdestruct method is reachable in the byte-code
- Severity is always set to
High
- Type is always set to
Unknown
- Metadata:
tx_hash
- hash of the transactionnew_implementation
- address of the new implementation
-
CONTRACT-INIT
- Fired when a contract is initialized by the TransferOwnership event where the previous owner was 0x0000000000000000000000000000000000000000
- Severity is always set to
Medium
- Type is always set to
Info
- Metadata:
tx_hash
- hash of the transactionnew_owner
- address of the new ownercontract
- address of the implementation
- Python:
3.10
npm start
This attack has not, as far as we know, been executed on chain.
You can test the agent using
npm test
There are 6 test that should pass:
test_returns_main_exploit_finding()
test_returns_finding_if_logic_contract_not_initialized()
test_returns_finding_if_new_logic_contract_can_be_selfdestructed()
test_returns_finding_if_contract_was_initialized()
test_returns_zero_finding_if_upgraded_event_is_correct_and_code_cant_selfdestruct()
test_returns_zero_finding_if_logic_contract_is_initialized_already()
For these purposes, web3 and event mocks are used. You can check web3 mock in src/test/web3_mock.py
and events mocks in src/test/agent_test.py