The _requireAuthorised function is a critical security check in the OwnershipNFTs contract, used to validate whether an address is allowed to transfer a specific token.
The authorization check in _requireAuthorised contains a logical error in its implementation of the ERC721 standard's approval mechanism.
function _requireAuthorised(address _from, uint256 _tokenId) internal view {
bool isAllowed =
msg.sender == _from ||
isApprovedForAll[_from][msg.sender] ||
msg.sender == getApproved[_tokenId];
require(isAllowed, "not allowed");
require(ownerOf(_tokenId) == _from, "_from is not the owner!");
}
The function checks if msg.sender == getApproved[_tokenId], but it should be checking if msg.sender == getApproved[_tokenId] && getApproved[_tokenId] != address(0). The current implementation allows transfers even when getApproved[_tokenId] is set to the zero address, which should not be considered a valid approval.
Impact
This bug could allow unauthorized transfers of tokens in certain scenarios, potentially leading to loss of assets for token owners.
Scenario
Alice owns token #123
getApproved[123] is set to address(0) (default value, meaning no specific address is approved)
Bob calls transferFrom(alice, bob, 123)
The transfer succeeds incorrectly because msg.sender (Bob) == getApproved[123] (address(0))
Fix
Modify the _requireAuthorised function to correctly check for a non-zero approved address:
function _requireAuthorised(address _from, uint256 _tokenId) internal view {
bool isAllowed =
msg.sender == _from ||
isApprovedForAll[_from][msg.sender] ||
(msg.sender == getApproved[_tokenId] && getApproved[_tokenId] != address(0));
require(isAllowed, "not allowed");
require(ownerOf(_tokenId) == _from, "_from is not the owner!");
}
Lines of code
https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L98
Vulnerability details
Summary
The
_requireAuthorised
function is a critical security check in the OwnershipNFTs contract, used to validate whether an address is allowed to transfer a specific token.The authorization check in
_requireAuthorised
contains a logical error in its implementation of the ERC721 standard's approval mechanism.Code Snippet
https://github.com/code-423n4/2024-08-superposition/blob/main/pkg/sol/OwnershipNFTs.sol#L98
The function checks if
msg.sender == getApproved[_tokenId]
, but it should be checking ifmsg.sender == getApproved[_tokenId] && getApproved[_tokenId] != address(0)
. The current implementation allows transfers even whengetApproved[_tokenId]
is set to the zero address, which should not be considered a valid approval.Impact
This bug could allow unauthorized transfers of tokens in certain scenarios, potentially leading to loss of assets for token owners.
Scenario
getApproved[123]
is set toaddress(0)
(default value, meaning no specific address is approved)transferFrom(alice, bob, 123)
msg.sender (Bob) == getApproved[123] (address(0))
Fix
Modify the
_requireAuthorised
function to correctly check for a non-zero approved address:Assessed type
Token-Transfer