T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:879
- Finding
- Server-Supplied Solana Transactions Are Signed Without Semantic Validation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md`, lines 879-887 and 1131-1157 **Vulnerability Type**: Blind signing of remotely supplied blockchain transactions **Risk Level**: High ### Vulnerable Code ```javascript function signVersionedTx(swapTxBase58) { const txBytes = bs58.decode(swapTxBase58); const tx = VersionedTransaction.deserialize(txBytes); tx.sign([getWallet()]); const signedBytes = tx.serialize(); return Buffer.from(signedBytes).toString('base64'); } ``` The function is invoked on the transaction supplied in an authenticated WebSocket fill: ```javascript async function handleOrderFilled(msg) { try { assertSchema(validateOrderFilled, msg, 'order_filled message'); } catch (e) { log({ step: 'order_fill_error', order_id: msg.order_id || 'unknown', error: e.message }); return; } const { order_id, order_type, triggered_mcap, filled_mcap, token_address } = msg; const swap_tx = msg.data?.swap_tx; log({ step: 'order_filled', order_id, order_type, token: token_address, triggered_mcap, filled_mcap }); if (msg.already_dispatched) { log({ step: 'order_fill_skipped', order_id, reason: 'already_dispatched' }); return; } // Verify server_signature before signing or submitting. const verified = await verifyOrderFilledSignature(msg); if (!verified) { log({ step: 'order_fill_skipped', order_id, reason: 'server_signature_verification_failed' }); return; } if (!swap_tx) { log({ step: 'order_fill_error', order_id, error: 'missing swap_tx' }); return; } // Staleness check (all fills; skip ratio when filled_mcap is 0 or null) if (filled_mcap != null && filled_mcap > 0 && triggered_mcap != null && triggered_mcap / filled_mcap < 0.85) { log({ step: 'order_fill_skipped', order_id, reason: 'stale', triggered_mcap, filled_mcap }); return; } const signedBase64 = signVersionedTx(swap_tx); const result = await submitTx(signedBase64, { token: token_address, action ...[truncated 3194 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Perform semantic transaction validation before signing** - Deserialize the transaction and resolve all static and address-lookup-table account keys. - Decode every instruction. - Reject unknown or unexpected program IDs. - Verify that the wallet is only a signer where explicitly required. - Verify the fee payer and impose a maximum transaction fee. 2. **Bind the transaction to the requested trade** - Confirm that the token mint matches the requested token. - Confirm that buy and sell directions match the original request or stored order. - Verify source and destination token accounts and their owners. - Enforce maximum input and minimum output amounts locally. - Check that slippage does not exceed the locally approved limit. - Confirm that SOL and token transfers remain within configured per-trade limits. 3. **Reject dangerous or unrelated instructions** - Reject unexpected system transfers, authority changes, token approvals, account closures, durable nonce operations, and arbitrary program invocations. - Maintain a narrowly scoped allowlist of reviewed swap programs and instruction types. - Reject transactions containing extra instructions that are unnecessary for the expected swap. 4. **Validate address lookup tables** - Resolve lookup tables through a trusted RPC endpoint. - Include the resolved accounts in policy checks. - Reject missing, changed, or unapproved lookup table entries. 5. **Add independent intent verification** - Persist the original order parameters locally. - Compare every fill transaction with the locally stored order rather than trusting message metadata alone. - Present a human-readable transaction summary and require confirmation when recipients, programs, amounts, or fees materially differ from expectations. 6. **Reduce wallet exposure** - Use a dedicated, low-balance trading wallet rather than a primary wallet. - Prefer a hardw ...[truncated 476 chars]
