Submitted by GimelSec, also found by csanuragjain, Czar102, Lambda, minhquanym, and shenwilly
LibDiamond.sol#L100-L103
LibDiamond.sol#L71-L79
LibDiamond.sol#L83-L90
Normally, diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] will be set in LibDiamond.proposeDiamondCut(). Then in LibDiamond.diamondCut(), it checks that diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] < block.timestamp.
However, LibDiamond.rescindDiamondCut() will set diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] to 0. Which can easily pass the check in diamondCut(). But rescindDiamondCut should rescind _diamondCut. In conclusion, using rescindDiamondCut() can easily bypass the delay time.
Moreover, if proposeDiamondCut() has never been called, the check for delay time is always passed.
diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] will be set in LibDiamond.proposeDiamondCut()
LibDiamond.sol#L71-L79
Then in LibDiamond.diamondCut(), it checks that diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] < block.timestamp
LibDiamond.sol#L100-L103
However, LibDiamond.rescindDiamondCut() will set diamondStorage().acceptanceTimes[keccak256(abi.encode(_diamondCut))] to 0. Which can easily pass the check in diamondCut()
LibDiamond.sol#L83-L90
function rescindDiamondCut(
IDiamondCut.FacetCut[] memory diamondCut,
address _init,
bytes memory _calldata
) internal {
diamondStorage().acceptanceTimes[keccak256(abi.encode(diamondCut))] = 0;
emit DiamondCutRescinded(_diamondCut, _init, _calldata);
}
Add another check in diamondCut
LayneHaber (Connext) confirmed
jakekidd (Connext) resolved:
0xleastwood (judge) decreased severity to Medium and commented:
