# V3Vault::transform does not validate the data input and allows a depositor to exploit any position approved on the transformer

V3Vault.transform only validates the outer tokenId, so any vault depositor can pass another user's transformer-approved NFT inside calldata and manipulate their position.

- Payout: Contest reward
- Severity: high
- Program: Revert Lend
- Credited: b0g0
- Disclosed: 2024-05-22
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2024-03-revert-lend-findings/issues/214
- Library page: https://bugbountylibrary.com/r/c4%3A2024-03-revert-lend%3AH-03
- 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:** V3Vault.transform / AutoCompound transformer (Solidity, Uniswap V3 NFT positions)
**Root cause:** transform() checks ownership of the tokenId argument but never verifies that the tokenId encoded in the arbitrary `data` calldata matches it, so the transformer acts on a different NFT.
**Steps:**
1. Alice approves her ALICE_NFT to the AutoCompound transformer (delegated to Revert bots).
2. Bob opens any position in the vault via `vault.create(BOB_NFT, Bob)` to gain transform rights.
3. Bob calls `vault.transform(BOB_NFT, address(autoCompound), abi.encodeWithSelector(AutoCompound.execute.selector, params))` where params.tokenId = ALICE_NFT.
4. transform approves the transformer for BOB_NFT but the transformer executes on ALICE_NFT, applying Bob's chosen params.
**How found:** Code review of transform(): noticed the tokenId parameter is validated for ownership but the calldata passed to the transformer is opaque and unchecked, so the inner tokenId can differ.
**Exploitation:** Attacker with any vault position crafts calldata for an approved transformer (e.g. AutoCompound.execute) encoding a victim's delegated NFT id; the transformer operates on the victim position, collecting repeated fees or executing unfavorable swaps to drain value.
**Escalation:** Repeat calls to harvest AutoCompound fees repeatedly, or manipulate swap0To1/amountIn to extract value from the victim's position.
**Insight:** When a contract forwards arbitrary calldata to a trusted module after approving it, check whether the module's target identifier (tokenId, position, account) is bound to the validated outer argument; mismatched inner/outer IDs are a classic confused-deputy pattern.
