# Malicious actor can steal any actively rented NFT and freeze the rental payments (of the affected rentals) in the escrow contract

stopRent lacks order-existence check before NFT reclamation, letting a fake PAY order be created mid-callback to steal any actively rented NFT and freeze escrow payments.

- Payout: Contest reward
- Severity: high
- Program: reNFT
- Credited: JCN
- Disclosed: 2024-03-20
- Write-up quality: 9/10
- Original: https://github.com/code-423n4/2024-01-renft-findings/issues/418
- Library page: https://bugbountylibrary.com/r/c4%3A2024-01-renft%3AH-05
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:business-logic vuln:signature-replay

**Target:** Stop.sol stopRent/stopRentBatch, Reclaimer, Signer EIP-712 hashing
**Root cause:** stopRent validates only orderType/endTimestamp/lender and reclaims the NFT before checking the order exists in storage; the orderHash omits rentalWallet, so a non-existent order can be created during the lender's onERC721Received callback and then settled/removed. Non-EIP-712 metadata hashing lets one signature be reused across order types.
**Steps:**
1. Deploy attackerContract and a protocol safe (attacker safe) via `Factory::deployRentalSafe` with attackerContract as owner.
2. Obtain a valid server-side RentPayload signature via front-end using any order, setting intendedFulfiller=attackerContract and fulfillment.recipient=attacker safe; reuse it for PAY and PAYEE since orderType is not hashed.
3. Call `stopRent` with a fabricated PAY RentalOrder: lender=attackerContract, rentalWallet=victim safe, items=the victim's rented NFT, hooks empty.
4. During `_reclaimRentedItems`, victim safe delegatecalls reclaimRentalOrder and transfers the NFT to attackerContract, triggering onERC721Received.
5. In the callback, create matching PAY/PAYEE orders, fulfill via `Seaport::matchAdvancedOrders` with the reused signature, sending NFT to attacker safe and 1 wei payment to escrow; orderHash stored.
6. stopRent continues: `settlePayment` pays attackerContract, `removeRentals` deletes the orderHash; NFT frozen in attacker safe, victim's escrow payment frozen.
**How found:** Code review of Stop.sol: noticed `_validateRentalCanBeStoped` only checks orderType/endTimestamp/lender and that `_reclaimRentedItems` transfers the NFT before any storage existence check; then traced `_deriveRentalOrderHash` and saw rentalWallet omitted, and `_deriveOrderMetadataHash` omitting orderType/emittedExtraData, enabling signature reuse and mid-callback order creation.
**Exploitation:** Attacker needs a protocol-deployed safe they own and one valid server-side signature (reusable due to non-EIP-712 metadata hash). They fabricate a PAY order pointing at a victim's actively rented NFT, call stopRent as lender; the reclamation delegatecall moves the NFT to the attacker contract, whose receive callback atomically creates and fulfills a real rental order (1 wei) so the subsequent settlePayment and removeRentals succeed. NFT ends in attacker safe, victim's rental payment stuck in escrow.
**Escalation:** Use `stopRentBatch` to steal and freeze multiple actively rented NFTs and their escrow payments in one transaction.
**Insight:** When a stop/cancel path transfers assets before verifying the order exists in storage, check whether the transfer callback (ERC721/1155 receive) can create the very order being validated; also check whether the order hash omits fields (like rentalWallet) that the stop path trusts.
