T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:69
- Finding
- Unvalidated Remote Blockchain Transactions May Cause Unauthorized Asset Transfers<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 69–97 **Vulnerability Type**: Trusting remotely generated transaction payloads without independent validation **Risk Level**: High ### Vulnerable Code ```markdown ### EVM transaction (`build_swap_tx`) ```json { "transactions": [ { "to": "0x...", "data": "0x...", "value": "0x0", "description": "Approve WETH" }, { "to": "0x...", "data": "0x...", "value": "0x0", "description": "Swap WETH → USDC" } ], "amount_out_estimated": "243.52", "amount_out_minimum": "241.1" } ``` **Execute `transactions` in order.** Each tx must confirm before sending the next. ### Sui transaction (`build_swap_tx`) ```json { "tx_bytes": "<base64 PTB>", "instructions": ["Pass tx_bytes to any Sui wallet to sign and submit."] } ``` Pass `tx_bytes` to Privy `send_sui_transaction` or the user's Sui wallet. ### Solana transaction (`build_swap_tx`) ```json { "transaction": "<base64 VersionedTransaction>", "amount_in": "0.1", "amount_out": "14.83" } ``` Pass `transaction` to the user's Solana wallet or Privy `sendTransaction`. ``` ### Technical Analysis The skill instructs the agent to execute or forward opaque transaction payloads generated by the remote Arsenal service. For EVM transactions, it requires transactions to be executed in order but does not require decoding or validating the destination address, chain ID, function selector, calldata arguments, native-token value, token approval amount, or recipient. For Sui and Solana, serialized transaction bytes are passed directly to a wallet or signing service without requiring inspection of their instructions or expected state changes. The descriptions, estimated output, and transaction payloads all originate from the same remote response. Consequently, a human-readable description such as `Approve WETH` does not prove that the associated calldata performs only that operation. Confirmation of an earlier quote also does not establish that a subse ...[truncated 2190 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Decode every transaction before signing** - Decode EVM function selectors and calldata arguments. - Decode every Sui programmable transaction block command. - Decode all Solana instructions, account roles, program IDs, and address lookup tables. - Reject payloads that cannot be fully decoded. 2. **Enforce explicit allowlists** - Allowlist supported chain IDs, router addresses, token contracts, Sui packages, Solana program IDs, and permitted function selectors. - Reject proxy, delegate-call, or arbitrary execution routes unless they are specifically required and independently verified. 3. **Verify transaction intent** - Compare input and output tokens, amounts, recipients, slippage, minimum output, chain, and sender with the user-confirmed quote. - Ensure the transaction does not contain extra transfers, approvals, signers, writable accounts, or contract calls. - Verify native-token `value` independently rather than trusting the remote response. 4. **Constrain token approvals** - Prefer exact-amount approvals. - Reject unlimited approvals unless the user explicitly requests and separately confirms them. - Confirm that the approved spender is the expected, allowlisted protocol contract. - Recommend revocation after use when a persistent approval is unavoidable. 5. **Simulate before submission** - Simulate transactions using an independent RPC provider. - Calculate expected balance and allowance changes. - Reject transactions whose simulation differs from the confirmed operation or produces unexplained state changes. 6. **Require final informed consent** - Display independently decoded recipients, contracts, amounts, approvals, fees, and expected balance changes. - Obtain explicit user confirmation for the final decoded transaction, not only for the preliminary quote. - Validate and confirm every transaction in a multi-transaction sequence independently. 7. **Fail ...[truncated 271 chars]
