ERC-165 Interface Spoofing Remediation
Overview
Related Detector: ERC-165 Interface Spoofing
supportsInterface(bytes4) is a self-report: a contract can return true for any interface id, whether or not it implements the behaviour. Routers, marketplaces, and bridges that branch on the result can be tricked into treating a hostile contract as a standard token. The remediation is to treat ERC-165 as a hint, not proof — verify the behaviour you depend on, and never grant trust on the flag alone.
Recommended Fix
Before (Vulnerable)
function list(address nft, uint256 id) external {
// A malicious contract can return true here without behaving like an ERC-721.
require(IERC165(nft).supportsInterface(type(IERC721).interfaceId), "Not ERC721");
_escrow(nft, id);
}
After (Fixed — verify behaviour and outcomes)
function list(address nft, uint256 id) external {
require(nft.code.length > 0, "Not a contract");
// Confirm the interface claim, then rely on the actual transfer succeeding and
// the post-conditions holding, not on the self-reported flag.
try IERC721(nft).ownerOf(id) returns (address owner) {
require(owner == msg.sender, "Not owner");
} catch {
revert("Not ERC721");
}
IERC721(nft).transferFrom(msg.sender, address(this), id);
require(IERC721(nft).ownerOf(id) == address(this), "Escrow failed");
}
Base authorization and accounting on verified outcomes (ownership before and after a transfer), so a spoofed supportsInterface cannot buy the attacker anything.
Common Mistakes
- Using
supportsInterfaceas an access-control gate rather than a capability hint. - Checking the interface id but skipping the post-condition check that the operation actually did what a real token would do.
- Assuming an ERC-165
trueimplies a specific fee or royalty behaviour (e.g. ERC-2981) without validating the returned values.