Lack of Access Control
Jump to navigation
Jump to search
It is a classic vulnerability that mostly occurs due to a development error. It includes: a forgotten modifier, excessive role rights, unrestricted function access, etc.
Example
Consider the following functions from the Code4rena Maia DAO contest[1]:
function call(Call[] calldata calls) external override requiresApprovedCaller returns (bytes[] memory returnData) {
uint256 length = calls.length;
returnData = new bytes[](length);
for (uint256 i = 0; i < length;) {
bool success;
Call calldata _call = calls[i];
if (isContract(_call.target)) (success, returnData[i]) = _call.target.call(_call.callData);
if (!success) revert CallFailed();
unchecked {
++i;
}
}
}
function payableCall(PayableCall[] calldata calls) public payable returns (bytes[] memory returnData) {
uint256 valAccumulator;
uint256 length = calls.length;
returnData = new bytes[](length);
PayableCall calldata _call;
for (uint256 i = 0; i < length;) {
_call = calls[i];
uint256 val = _call.value;
// Humanity will be a Type V Kardashev Civilization before this overflows - andreas
// ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256
unchecked {
valAccumulator += val;
}
bool success;
if (isContract(_call.target)) (success, returnData[i]) = _call.target.call{value: val}(_call.callData);
if (!success) revert CallFailed();
unchecked {
++i;
}
}
// Finally, make sure the msg.value = SUM(call[0...i].value)
if (msg.value != valAccumulator) revert CallFailed();
}
As you can see, the second function, in contrast to the first, does not use the requiresApprovedCaller
modifier which leads to a Lack of Access Control issue because anybody can call it and drain ERC20/721/1155 tokens from the contract (see the report).