Issue:
The callExternalContract
function allows an account with OWP_FACTORY_ROLE
to execute arbitrary external calls, creating a significant security risk if this role is compromised. This issue is similar to the previously identified EXTERNAL_CALLER
risk in MembershipFactory
.
Location:
function callExternalContract(address contractAddress, bytes memory data) external payable onlyRole(OWP_FACTORY_ROLE) returns (bytes memory) {
(bool success, bytes memory returndata) = contractAddress.call{value: msg.value}(data);
require(success, "External call failed");
return returndata;
}
Exploit Code:
A malicious user with the OWP_FACTORY_ROLE
could exploit callExternalContract
to drain tokens from the MembershipERC1155
contract or perform unauthorized actions.
address targetERC20 = ;
bytes memory data = abi.encodeWithSignature("transfer(address,uint256)", msg.sender, 1000 ether);
membershipERC1155.callExternalContract(targetERC20, data);
Impact:
This could allow an attacker to drain funds or perform unauthorized operations, representing a high-security risk.
Tools Used
Manual review.
Recommendation:
Restrict callExternalContract
to a set of whitelisted contracts or functions:
function callExternalContract(address contractAddress, bytes memory data) external payable onlyRole(OWP_FACTORY_ROLE) returns (bytes memory) {
require(isWhitelistedContract(contractAddress), "Unauthorized contract");
bytes4 selector = bytes4(data);
require(isAllowedFunction(selector), "Function not allowed");
(bool success, bytes memory returndata) = contractAddress.call{value: msg.value}(data);
require(success, "External call failed");
return returndata;
}
function isWhitelistedContract(address contractAddress) internal view returns (bool) {
}
function isAllowedFunction(bytes4 selector) internal view returns (bool) {
}