T09 · Insecure Skill Coding Practices
- Location
SKILL.md:369- Finding
Persistent Unlimited Token Allowances Expand the Asset-Transfer Attack Surface
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 369–399
Vulnerability Type: Persistent and excessive token authorization
Risk Level: HighVulnerable Code
typescript const MAX_UINT256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') if (permit2Allowance < MAX_UINT256 / 2n) { const hash = await walletClient.writeContract({ address: tokenAddress, abi: erc20Abi, functionName: 'approve', args: [PERMIT2_ADDRESS, MAX_UINT256], }) await publicClient.waitForTransactionReceipt({ hash }) console.log('✅ Permit2 approved') } // Step 2: Approve the Universal Router via Permit2 (per-swap, via signature OR transaction) // The Universal Router SDK handles this via inputTokenPermit in options. // For simplicity, approve the Universal Router directly instead: const routerAddress = getUniversalRouterAddress(chainId) as `0x${string}` const routerAllowance = await publicClient.readContract({ address: tokenAddress, abi: erc20Abi, functionName: 'allowance', args: [owner, routerAddress], }) if (routerAllowance < MAX_UINT256 / 2n) { const hash = await walletClient.writeContract({ address: tokenAddress, abi: erc20Abi, functionName: 'approve', args: [routerAddress, MAX_UINT256], }) await publicClient.waitForTransactionReceipt({ hash }) console.log('✅ Universal Router approved') }Technical Analysis
The example grants the maximum possible ERC-20 allowance to both Permit2 and the Universal Router. These authorizations are substantially broader than the amount required for an individual swap and can remain valid after the swap completes.
Approving both Permit2 and the router also creates two independent authorization paths. This exceeds minimum privilege because a swap can instead use an exact-amount approval or a constrained Permit2 authorization. The code only checks whether the ...[truncated 1625 chars]
- Remediation
View remediation
Remediation Suggestions
- Approve only the exact input amount required for the pending swap.
- Prefer a Permit2 signature constrained by token, exact amount, spender, chain ID, nonce, and a short expiration time.
- Do not approve both Permit2 and the Universal Router unless the selected integration explicitly requires both authorization paths.
- Present the spender address, allowance amount, chain, and expiration to the user before requesting authorization.
- Validate router and Permit2 addresses against a chain-specific, audited allowlist.
- Provide an allowance-revocation workflow and recommend revoking unused persistent approvals.
- If an unlimited approval remains available as an opt-in convenience, clearly warn that it is persistent and can expose the token's entire wallet balance.
