T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/swap.js:242
- Finding
- API-Controlled ERC-20 Approval Amount Is Not Bounded to the Requested Swap<![CDATA[ ## Vulnerability Details **File Location**: `scripts/swap.js:242-259` **Vulnerability Type**: Excessive token allowance / insufficient transaction validation **Risk Level**: High ### Vulnerable Code ```js function validateApprove(tx, isFirstOfPair) { if (tx.to.toLowerCase() !== tokenIn.address.toLowerCase()) fail(); const data = tx.data.toLowerCase(); if (data.length !== 138) fail(); if (!data.startsWith(APPROVE_SELECTOR)) fail(); // approve(spender, amount): selector(4B) + spender word(32B) + amount(32B). // Spender address = last 20 bytes of spender word -> hex chars 34..74. const spender = "0x" + data.slice(34, 74); if (spender !== ROUTER_ADDRESS) fail(); // USDT-style reset pattern: a pair of approves where the first sets allowance // to 0 (required by tokens that disallow direct allowance change) and the // second sets the new non-zero allowance. A solo approve must be non-zero. const amount = BigInt("0x" + data.slice(74, 138)); if (isFirstOfPair) { if (amount !== 0n) fail(); } else { if (amount === 0n) fail(); } if (BigInt(tx.value) !== 0n) fail(); } ``` ### Technical Analysis The Skill correctly limits the approval spender to the hardcoded AIDEX router, but it does not limit the allowance amount. For a normal approval, any nonzero value is accepted, including the maximum `uint256` value. The API constructs the unsigned approval transaction. Consequently, a compromised or faulty API can return an unlimited approval even when the user requested only a small swap. This approval passes local validation because the validator checks only that the amount is nonzero. The resulting permission exceeds the minimum authority necessary to execute the requested swap. An exact or narrowly bounded allowance would be sufficient. ### Attack Path 1. A user requests a swap of a limited amount of an ERC-20 token. 2. The AIDEX API returns an approval transaction calling: `approve(ROUTER_ADDRESS, 2^256 - 1)`. 3. ...[truncated 979 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Require the approved amount to equal the exact base-unit value of `amountIn`. 2. If protocol behavior requires a buffer, enforce a small, explicitly documented maximum rather than accepting any nonzero value. 3. Reject `MaxUint256` and other unlimited approvals by default. 4. If unlimited approval is offered as an optimization, make it an explicit user-selected option and clearly disclose its persistence and risk. 5. Consider generating and broadcasting a post-swap allowance revocation transaction when an exact allowance cannot be used. 6. Add tests proving that oversized and unlimited approvals are rejected while exact approvals and valid USDT-style zero-reset sequences remain supported. ]]>
