diff --git a/contracts/src/Denylist.sol b/contracts/src/Denylist.sol index bf0292d1..9b2224f2 100644 --- a/contracts/src/Denylist.sol +++ b/contracts/src/Denylist.sol @@ -29,6 +29,8 @@ contract Denylist is Initializable, Ownable2StepUpgradeable { error CannotDenylistOwner(); /// @notice Thrown when caller is not a denylister error CallerIsNotDenylister(); + /// @notice Thrown when caller is denylisted + error CallerIsDenylisted(); /// @notice Thrown when address is zero error ZeroAddress(); @@ -56,6 +58,7 @@ contract Denylist is Initializable, Ownable2StepUpgradeable { modifier onlyDenylister() { DenylistStorage storage $ = _getDenylistStorage(); if (!$.denylisters[msg.sender]) revert CallerIsNotDenylister(); + if ($.denylisted[msg.sender]) revert CallerIsDenylisted(); _; } diff --git a/contracts/test/Denylist.t.sol b/contracts/test/Denylist.t.sol index 49123734..26ee9f80 100644 --- a/contracts/test/Denylist.t.sol +++ b/contracts/test/Denylist.t.sol @@ -186,6 +186,37 @@ contract DenylistTest is Test { assertTrue(denylist.isDenylisted(alice)); } + function test_Fixed_DenylistedDenylisterCannotMutate() public { + // owner grants denylister to two accounts (compromised, rescuer) + address compromised = address(100); + address rescuer = address(101); + + vm.startPrank(owner); + denylist.addDenylister(compromised); + denylist.addDenylister(rescuer); + vm.stopPrank(); + + // rescuer denylists compromised + address[] memory accountsToDenylist = new address[](1); + accountsToDenylist[0] = compromised; + vm.prank(rescuer); + denylist.denylist(accountsToDenylist); + + // compromised tries to un-denylist themselves + address[] memory accountsToUnDenylist = new address[](1); + accountsToUnDenylist[0] = compromised; + vm.prank(compromised); + vm.expectRevert(Denylist.CallerIsDenylisted.selector); + denylist.unDenylist(accountsToUnDenylist); + + // compromised also cannot denylist anyone else + address[] memory otherAccounts = new address[](1); + otherAccounts[0] = alice; + vm.prank(compromised); + vm.expectRevert(Denylist.CallerIsDenylisted.selector); + denylist.denylist(otherAccounts); + } + // ============ Add / Remove denylisters (onlyOwner) ============ function test_AddDenylister_OnlyOwner_Success() public {