# Escrow contract can be drained by creating rentals that bypass execution invariant checks

reNFT Create.sol skips execution invariant checks when Seaport produces zero executions, letting fake rentals be stored and stopped to drain escrowed ERC20 payments.

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

**Target:** Create.sol order validation / PaymentEscrow
**Root cause:** Create::validateOrder relies on Seaport totalExecutions to verify ERC20 goes to ESCRW and NFTs to the Safe, but Seaport ignores executions where to==from, so a self-matched PAY/PAYEE pair yields zero executions and no recipient checks run while STORE still records the rental and increments escrow balance.
**Steps:**
1. Carol signs a PAY order offering NFT + ERC20.
2. Carol signs a PAYEE counterpart with recipients set to her own address instead of Safe/ESCRW.
3. Match both orders via forked Seaport so all offers/considerations share one address, producing totalExecutions length 0.
4. Create::validateOrder runs with no executions, skipping _executionInvariantChecks; STORE adds rental and escrow deposit is incremented without any transfer.
5. Warp past expiration, transfer NFT to Safe so stopRent succeeds, then call stopRent to withdraw the phantom escrow balance, draining ERC20 from PaymentEscrow.
**How found:** Reading Create.sol's reliance on Seaport totalExecutions for recipient invariant checks and recalling Seaport docs point 9 that executions with to==from are ignored, hypothesizing a self-matched order yields zero executions.
**Exploitation:** Attacker crafts self-matched PAY/PAYEE orders so no tokens move but a rental is registered with an inflated escrow balance, then stops the rental after expiry to withdraw ERC20 held by PaymentEscrow for other rentals.
**Escalation:** Can target any token/amount matching escrow balances; also works with ERC1155 and partial-fulfillment variants leaving one real execution.
**Insight:** When a protocol trusts a marketplace's fulfillment array to enforce recipient invariants, check whether the marketplace can emit zero or fewer executions (self-matches, to==from skips) so the invariant loop never runs while state is still committed.
