# Collateral NFT deposited to a wrong address, when transferred directly to PaprController

PaprController's onERC721Received used the operator/approved caller as vault owner instead of the `from` argument, so NFTs sent via operator were credited to the wrong vault.

- Payout: Contest reward
- Severity: high
- Program: Backed Protocol
- Credited: Jeiwan
- Disclosed: 2023-01-31
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2022-12-backed-findings/issues/183
- Library page: https://bugbountylibrary.com/r/c4%3A2022-12-backed%3AH-03
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** PaprController ERC721 receive hook (Solidity contract)
**Root cause:** onERC721Received read the first parameter (the msg.sender/operator) as the depositor instead of the second `from` parameter, which is the actual NFT owner.
**Steps:**
1. Borrower calls `nft.setApprovalForAll(operator, true)` (or `nft.approve(approved, collateralId)`)
2. Operator/approved calls `nft.safeTransferFrom(borrower, address(controller), collateralId, data)`
3. Controller's onERC721Received credits vault of operator/approved instead of borrower
4. Assert `controller.vaultInfo(operator, collateral.addr).count == 1` and borrower vault count == 0
**How found:** Code review of the onERC721Received hook against OpenZeppelin's ERC721 safeTransferFrom, which passes `_msgSender()` as first arg and `from` as second; noticed the hook used the first argument as owner.
**Exploitation:** An approved address or operator transfers the victim's NFT directly to PaprController; the hook records the deposit under the caller's vault, so the NFT is attributed to the wrong account and the true owner loses the collateral.
**Insight:** When auditing ERC721Receiver hooks, verify which parameter is the true owner: safeTransferFrom passes (operator, from, tokenId, data), so the depositor is the second arg, not msg.sender.
