T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/solana.js:149
- Finding
- Human-confirmation and mainnet safeguards can be bypassed through an agent-controlled option<![CDATA[ ## Vulnerability Details **File Location**: `scripts/solana.js:149-175`, `scripts/solana.js:233` **Vulnerability Type**: Security control bypass **Risk Level**: High ### Vulnerable Code ```javascript async function sendSol(privateKey, toAddress, amount, options = {}) { const { dryRun = true, skipConfirmation = false } = options; // SECURITY: Validate inputs if (!privateKey) { throw new Error('Private key is required'); } if (!toAddress || toAddress.length < 32) { throw new Error('Invalid recipient address'); } if (amount <= 0) { throw new Error('Amount must be positive'); } // SECURITY: Check max limits if (amount > MAX_SOL_PER_TX) { throw new Error(`Amount ${amount} SOL exceeds max limit of ${MAX_SOL_PER_TX} SOL`); } // SECURITY: Check testnet (warn if mainnet) const connection = getConnection(DEFAULT_RPC); if (!isTestNet(DEFAULT_RPC) && dryRun === false && !skipConfirmation) { console.warn('⚠️ WARNING: Running on MAINNET with real transactions!'); } // SECURITY: Require human confirmation for large amounts if (amount >= REQUIRE_HUMAN_CONFIRMATION && !skipConfirmation && dryRun === false) { throw new Error(`Amount ${amount} SOL requires human confirmation (threshold: ${REQUIRE_HUMAN_CONFIRMATION} SOL)`); } ``` The transaction is subsequently broadcast without any independent authorization check: ```javascript // Send real transaction const txSignature = await connection.sendRawTransaction(transaction.serialize()); ``` The bypass is also explicitly documented in `SKILL.md:91-94`: ```javascript // Skip human confirmation (for automated agents) await sendSol(key, to, amount, { dryRun: false, skipConfirmation: true }); ``` ### Technical Analysis The purported human-confirmation control is only a Boolean condition controlled by the same caller requesting the transaction. Setting `skipConfirmation` to `true` disables the large-transfer rejection. It also suppresses the mainnet ...[truncated 1864 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove `skipConfirmation` from all agent-controlled or generally accessible API parameters. 2. Implement an out-of-band approval service operated outside the agent’s trust boundary. 3. Require a short-lived, cryptographically signed approval token for transactions at or above the threshold. 4. Bind each approval to the network, sender, recipient, exact lamport amount, recent blockhash, expiration time, and a unique nonce. 5. Reject token reuse and fail closed if approval verification is unavailable. 6. Enforce a separate mainnet policy. Do not treat a warning as an authorization control. 7. Add cumulative limits, rate limits, recipient allowlists, and configurable daily spending limits. 8. Separate simulation and broadcast into distinct APIs, with the broadcast API requiring stronger authorization. 9. Add tests proving that caller-controlled options cannot bypass confirmation or mainnet restrictions. ]]>
