Open c4-submissions opened 1 year ago
GalloDaSballo marked the issue as satisfactory
GalloDaSballo removed the grade
0xfoobar (sponsor) confirmed
Need to double-check but looks plausible
In contrast to ERC721, which only allows the owner to change approve
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/ef3e7771a7e2d9b30234a57f96ee7acf5dddb9ed/contracts/token/ERC721/ERC721.sol#L448-L454
DT.approve
allows the operator to set themselves as approved, which can technically be undone via a multicall but may not be performed under normal usage
GalloDaSballo changed the severity to 2 (Med Risk)
Leaning towards Medium Severity as the finding requires:
approvesForAll
BobapprovalForAll
_approve
that Bob gave to selfNotice that any transfer would reset the approval as well
GalloDaSballo marked the issue as selected for report
A note about how ERC721 works: there are two different types of approvals. approve()
lets an account move a single tokenId, while setApprovalForAll()
marks an address as an operator to move all tokenIds. We can note the difference in the core OpenZeppelin ERC721 base contract, two separate mappings: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC721/ERC721.sol#L32-L34
So plausible that an operator could be permitted to add new tokenid-specific approvals, but see your point that OZ ERC721 doesn't allow this by default and so could lead to confusing states that are possible but not fun to get out of.
Lines of code
https://github.com/code-423n4/2023-09-delegate/blob/main/src/DelegateToken.sol#L134 https://github.com/code-423n4/2023-09-delegate/blob/main/src/DelegateToken.sol#L168 https://github.com/code-423n4/2023-09-delegate/blob/main/src/libraries/DelegateTokenStorageHelpers.sol#L149
Vulnerability details
Impact
There is no way to revoke the approval which given via
DelegateToken.approve(address,delegateTokenId)
. They can able call theDelegateToken.transferFrom
even the tokenHolder revoke the permission using theDelegateToken.setApprovalForAll
if the spender address is approved by the PT token ,we can call the
DelegateToken.withdraw
.Proof of Concept
Alice is the token Holder.
Alice approves Bob via
DelegateToken.setApprovalForAll(Bob,true)
.Bob approves himself using
DelegateToken.approve(Bob,delegateTokenId)
Alice revokes the Bob approval by calling
DelegateToken.setApprovalForAll(Bob,false);
Now Bob can still calls the
DelegateToken.transferFrom(Alice,to,delegateTokenId)
which is subjected to call only by approved address.The transfer will be successful.
Code details :
https://github.com/code-423n4/2023-09-delegate/blob/main/src/libraries/DelegateTokenStorageHelpers.sol#L143
Even after revoking the approval for operator using
setApprovalAll
thismsg.sender == readApproved(delegateTokenInfo, delegateTokenId)
will be true and able to calltransferFrom
function.**Test function :***
Tools Used
Manual Analysis
Recommended Mitigation Steps
If token Holder revokes the approval for a operator using
DelegateToken.setApprovalForAll
, revoke the all the approvals(DelegateToken.approve) which is done by the operator.Assessed type
Access Control