T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/sender_execute_order.js:66
- Finding
- Untrusted order metadata controls the token spender and swap execution target<![CDATA[ ## Vulnerability Details **File Location**: `scripts/sender_execute_order.js:66-71, 83-90, 143-159, 210-214` **Vulnerability Type**: Arbitrary contract approval and invocation through untrusted metadata **Risk Level**: High ### Vulnerable Code ```js function resolveSwapAddress(payload, order) { if (process.env.SWAP_ADDRESS) return process.env.SWAP_ADDRESS; const fromMeta = payload?.meta?.verifyingContract || payload?.meta?.swapContract; if (fromMeta) return fromMeta; const senderKind = String(order?.sender?.kind || '').toLowerCase(); if (senderKind === KIND_ERC721.toLowerCase()) return SWAP_ERC721; if (senderKind === KIND_ERC1155.toLowerCase()) return SWAP_ERC1155; return SWAP_DEFAULT; } ``` ```js const payload = JSON.parse(fs.readFileSync(path.resolve(IN), 'utf8')); const order = payload.order; const signature = payload.signature; const provider = new ethers.providers.JsonRpcProvider(RPC); const sender = new ethers.Wallet(SENDER_PRIVATE_KEY, provider); const swapAddress = resolveSwapAddress(payload, order); const swap = new ethers.Contract(swapAddress, SWAP_ABI, provider); ``` ```js if (allowance.lt(total)) { const tx = await senderToken.connect(sender).approve(swapAddress, total, { maxPriorityFeePerGas: feeOverrides.maxPriorityFeePerGas, maxFeePerGas: feeOverrides.maxFeePerGas, }); console.log('approveSenderAssetTx', tx.hash); await tx.wait(); } ``` ```js const tx = await swap.connect(sender).swap(recipient, maxRoyalty, orderForCall, { gasLimit, maxPriorityFeePerGas: feeOverrides.maxPriorityFeePerGas, maxFeePerGas: feeOverrides.maxFeePerGas, }); ``` ### Technical Analysis The sender script treats `meta.verifyingContract` or `meta.swapContract` from the input order file as an authoritative swap address. It does not verify that this value is one of the three documented Base mainnet AirSwap deployments. The EIP-712 signature check does not establish that the contract is trusted. An attacker can create an or ...[truncated 2115 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Define an immutable allowlist mapping each supported sender kind to its approved Base mainnet deployment. 2. Derive the swap address from the validated chain ID and sender kind rather than trusting order metadata. 3. Reject the order if `meta.verifyingContract`, `meta.swapContract`, or the compressed order's contract differs from the derived allowlisted address. 4. Verify that the connected network has chain ID `8453` before signing, approving, or broadcasting. 5. Optionally verify deployed runtime bytecode hashes against known deployment hashes. 6. Remove `SWAP_ADDRESS` overrides from production execution. If retained for development, require an explicit unsafe-development flag and prevent use with funded production wallets. 7. Perform all contract-address validation before querying token balances or issuing approvals. 8. Consider simulating the exact token balance changes through a trusted contract before granting approval. 9. Revoke any residual allowance after a failed execution where practical. ]]>
