T09 · Insecure Skill Coding Practices
- Location
references/REFERENCE.md:34- Finding
Blind Signing of Remotely Generated Swap Transactions
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md:47;references/REFERENCE.md:34-35, 42-79
Vulnerability Type: Insufficient validation of untrusted transaction data
Risk Level: HighThe documentation instructs integrators to use transaction data returned by the SushiSwap API exactly as provided:
text Use returned transaction data exactly as provided for simulation or executionThe reference implementation obtains transaction fields from the remote API and passes them directly to the wallet:
ts const data = await getSwap({ chainId: EvmChainId.ETHEREUM, tokenIn: '0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE', tokenOut: '0x6B3595068778DD592e39A122f4f5a5cF09C90fE2', sender: '0xYourAddressHere', amount: 1000000000000000000n, maxSlippage: 0.005, }) if (data.status === 'Success') { const { tx } = data const callResult = await publicClient.call({ account: tx.from, data: tx.data, to: tx.to, value: tx.value, }) console.log('Simulated output:', callResult) const PRIVATE_KEY = process.env.PRIVATE_KEY as Hex const walletClient = createWalletClient({ chain: mainnet, transport: http(), }) const hash = await walletClient.sendTransaction({ account: privateKeyToAccount(PRIVATE_KEY), data: tx.data, to: tx.to, value: tx.value, }) }Technical Analysis
The transaction destination, calldata, and native-token value are controlled by a response from an external API. The example does not independently verify:
- That
tx.tois an approved SushiSwap router for the selected chain. - That decoded calldata performs the requested swap.
- That input and output tokens match the user's request.
- That the input amount and minimum output are within approved limits.
- That the transaction recipient is the intended account.
- That token approvals are limited to the required amount and spender.
...[truncated 1730 chars]
- That
- Remediation
View remediation
Remediation Suggestions
- Treat every API-generated transaction as untrusted input.
- Maintain an authenticated allowlist of expected router addresses for each supported chain and reject any other
tx.tovalue. - Decode
tx.datausing the expected router ABI and verify the function selector and all relevant arguments. - Confirm the chain ID, sender, recipient, input token, output token, input amount, minimum output, deadline, slippage, and native-token value against the user's approved request.
- Validate that approvals use the intended spender and are limited to the minimum necessary amount and duration.
- Compare simulated asset and allowance changes against explicit invariants rather than relying only on successful execution.
- Display the decoded operation and expected asset changes to the user and require explicit confirmation before signing.
- Reject malformed, unexpected, or undecodable calldata.
- Use a wallet or policy engine capable of transaction simulation, human-readable decoding, contract allowlisting, and spending limits.
- Replace the instruction to use returned data “exactly as provided” with guidance requiring independent validation before execution.
