T09 · Insecure Skill Coding Practices
Error
- Location
- examples/swap-quote/README.md:57
- Finding
- Remote transactions are signed without validating their instructions<![CDATA[ ## Vulnerability Details **File Location**: `examples/swap-quote/README.md:57-70` **Additional Locations**: `examples/gasless-swap/README.md:46-58`, `examples/swap-bundle/README.md:45-58`, `docs/trading-bots.md:50-65`, `SKILL.md:636-647` **Vulnerability Type**: Blind signing of untrusted serialized Solana transactions **Risk Level**: High ### Vulnerable Code ```typescript if (!quote.txn) { throw new Error("No executable transaction — ensure user_account is set"); } const tx = VersionedTransaction.deserialize( Buffer.from(quote.txn, "base64") ); tx.sign([wallet]); const sig = await connection.sendRawTransaction(tx.serialize(), { maxRetries: 3, }); await connection.confirmTransaction(sig, "confirmed"); console.log("Swap confirmed:", sig); return sig; ``` The same unsafe pattern appears in the other listed locations: a transaction returned by `api.carbium.io` is decoded, signed with the user's wallet, and submitted without locally validating its contents. ### Technical Analysis The serialized transaction is generated by an external service and therefore crosses a trust boundary. Base64 decoding and successful deserialization establish only that the response has the correct wire format; they do not establish that the transaction performs the requested swap. Before signing, the examples do not verify: - Invoked program IDs against an allowlist. - Source and destination token mints. - User token accounts and transfer destinations. - Input amount and minimum output amount. - Fee payer, priority fee, Jito tip, or custom fee recipients. - Unexpected transfer, approval, close-account, or authority-changing instructions. - Address lookup tables and the accounts resolved through them. - Consistency between the displayed quote and the executable transaction. The wallet signature authorizes the transaction message received from the service. Consequently, compromise or malfunction of the transaction-generation service can transform an ordinary quot ...[truncated 1518 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Implement a strict transaction-verification layer before any signing operation: 1. Deserialize the transaction and resolve every static and lookup-table account. 2. Allowlist the exact Solana programs expected for the selected route. 3. Parse every instruction and reject unknown, unsupported, or partially decoded instructions. 4. Verify the signer and fee payer are the expected wallet. 5. Verify source and destination mints, token accounts, recipients, input amount, minimum output, slippage, fees, tips, and fee receivers against the user's approved quote. 6. Reject unexpected native SOL transfers, token approvals, authority changes, account closures, and additional signers. 7. Simulate the transaction and inspect balance changes before signing. Simulation should supplement, not replace, deterministic instruction validation. 8. Display or log a normalized transaction summary for explicit approval in interactive applications. 9. Apply transaction value limits and route-specific policy controls for unattended bots. 10. Fail closed whenever an instruction or account cannot be fully resolved and validated. Apply the same validation helper consistently to all examples and documentation that signs API-generated transactions. ]]>
