Closed code423n4 closed 1 year ago
minhquanym marked the issue as primary issue
CJ42 marked the issue as sponsor disputed
This is a known issue. https://github.com/code-423n4/2023-06-lukso/tree/main#general
trust1995 marked the issue as unsatisfactory: Out of scope
Lines of code
https://github.com/code-423n4/2023-06-lukso/blob/main/contracts/LSP7DigitalAsset/LSP7DigitalAssetCore.sol#L480-L496
Vulnerability details
Bug Description
Throughout the codebase, the protocol uses the
supportsERC165InterfaceUnchecked()
function from Openzeppelin'sERC165Checker.sol
to check for the support of ERC-165 interface IDs.However,
supportsERC165InterfaceUnchecked()
only checks if the call tosupportsInterface()
has a non-zero return value:ERC165Checker.sol#L116-L122
This might cause
supportsERC165InterfaceUnchecked()
to incorrectly return true for contracts that meet one of the following criteria:0x01ffc9a7
, which clashes withsupportsInterface(bytes4)
. This function must have a non-zero return value.In the protocol,
supportsERC165InterfaceUnchecked()
is mainly used to check if an address is compatible with LSP-1 before calling itsuniversalReceiver()
function.For example,
_notifyTokenReceiver()
inLSP7DigitalAssetCore.sol
ensures that the address receiving tokens is capable of handling them:LSP7DigitalAssetCore.sol#L480-L496
However, if the receiving contract meets one of the criteria mentioned above,
supportsERC165InterfaceUnchecked()
will incorrectly return true, even if the receiving contract does not support LSP-1.This would cause the transaction to revert when attempting to call
universalReceiver()
at theto
address. Therefore, theto
address will never be able to receive LSP7 tokens, even ifallowNonLSP1Recipient
is set totrue
.Note that the scenario demonstrated above is only one of the many possible impacts. As
supportsERC165InterfaceUnchecked()
is widely used throughout the codebase, such as intryNotifyUniversalReceiver()
, this pattern affects many LSPs:transferOwnership()
andacceptOwnership()
in LSP0 and LSP14 might not work.Additionally, if the contract implements a fallback function that returns non-zero
bytes
, the call touniversalReceiver()
will actually succeed. This is because theILSP1UniversalReceiver
interface expectsuniversalReceiver()
to returnbytes
:ILSP1UniversalReceiver.sol#L32-L35
This makes it possible to send LSP7/LSP8 tokens to contracts that don't implement LSP-1, even though
allowNonLSP1Recipient
is explicitly set tofalse
to disable such behavior.Impact
As
supportsERC165InterfaceUnchecked()
might incorrectly returntrue
for certain contracts, the functionality of LSP0, LSP1 and LSP14 might behave unexpectedly for these contracts, which could break its functionality.Note on severity
I am aware that usage of
supportsERC165InterfaceUnchecked()
is listed under the Publicly Known Issues in the contest's README. However, given that it could potentially break LSP functionality for certain contracts, I have decided to raise it as a medium severity finding.Proof of Concept
The following code contains two Foundry tests:
testERC165CheckPasses()
illustrates that a contract with a fallback function that returnsbytes
will pass bothsupportsERC165InterfaceUnchecked()
anduniversalReceiver()
.testERC165CheckCausesRevert()
demonstrates how a contract that contains a function with the same selector assupportsInterface(bytes4)
will revert.Recommended Mitigation
Consider using the
supportsERC165()
function instead, which accounts for such scenarios.Assessed type
Library