# _execBuyNftFromMarket() Need to determine if NFT can't already be in the contract

Particle's buyNftFromMarket only checks the NFT is owned by the contract after purchase, so a borrower can buy an unrelated NFT and still pass verification, repaying the lien while keeping the original NFT.

- Payout: Contest reward
- Severity: high
- Program: Particle Protocol
- Credited: bin2chen
- Disclosed: 2023-08-07
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-05-particle-findings/issues/15
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-particle%3AH-03
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** ParticleExchange buyNftFromMarket / _execBuyNftFromMarket
**Root cause:** _execBuyNftFromMarket verifies ownerOf(tokenId)==address(this) after the trade but never checks the NFT wasn't already held by the contract before the buy, so any pre-existing NFT satisfies the check.
**Steps:**
1. Alice supplies NFT_A as Lien[1] via _approveAndSupply.
2. Borrower sells NFT_A to marketplace via sellNftToMarket(1).
3. Jack buys NFT_A from marketplace and re-supplies it as Lien[2], so NFT_A is now owned by the contract.
4. Borrower calls buyNftFromMarket with tradeData instructing the marketplace to buy an unrelated NFT_K instead of NFT_A.
5. Post-trade check ownerOf(NFT_A)==address(this) passes (already true) and balance delta matches amount, so the lien is repaid and borrower keeps NFT_K.
**How found:** Code reading of _execBuyNftFromMarket's post-condition check; noticed the protocol doesn't restrict an NFT to a single lien, so the ownerOf assertion can be satisfied by a pre-existing NFT rather than the one actually purchased.
**Exploitation:** Borrower takes a lien against NFT_A, sells it, has a third party re-supply the same NFT to the contract, then calls buyNftFromMarket with tradeData that purchases a different cheap NFT. The ownerOf check passes because NFT_A is already in the contract, funds are spent on NFT_K, and the borrower recovers the loan amount while gaining NFT_K.
**Insight:** When a function verifies success by checking end-state (ownerOf == this, balance delta), also verify the pre-state differs; otherwise any pre-existing state satisfies the post-condition and the actual purchase can be redirected to an unrelated asset.
