T09 · Insecure Skill Coding Practices
- Location
- references/solana.md:336
- Finding
- Unvalidated Solana Transactions Are Signed and Broadcast by the Fee-Payer Service<![CDATA[ ## Vulnerability Details **File Location**: `references/solana.md:336-354` **Vulnerability Type**: Blind signing of attacker-controlled serialized transactions **Risk Level**: Critical ### Vulnerable Code ```tsx const response = await fetch('/api/sponsor', { method: 'POST', body: JSON.stringify({transaction: signed.serialize().toString('base64')}) }); ``` ```ts // API route: /api/sponsor const {transaction: serialized} = req.body; const transaction = Transaction.from(Buffer.from(serialized, 'base64')); // Sign with fee payer transaction.partialSign(feePayerKeypair); // Broadcast const connection = new Connection('https://api.mainnet-beta.solana.com'); const signature = await connection.sendRawTransaction(transaction.serialize()); ``` ### Technical Analysis The sponsorship endpoint deserializes a transaction supplied entirely by the client, adds the server fee-payer signature, and broadcasts it without validating its contents. Base64 decoding is not itself code execution or obfuscation in this case. The decoded value is a Solana transaction. However, applying `partialSign(feePayerKeypair)` authorizes every instruction for which the fee-payer key is declared as a required signer. The example does not demonstrate: - Authentication or authorization of the requesting user. - Verification that the declared fee payer equals the expected server wallet. - Validation of program IDs, instructions, accounts, recipients, or amounts. - Rejection of instructions that transfer assets owned by the fee-payer account. - Limits on compute budget, transaction fees, request frequency, or cumulative sponsored expenditure. - Transaction simulation before signing. - Request-size restrictions or replay protections. Signing opaque client-generated transactions violates least privilege because the endpoint grants general fee-payer signing authority rather than authorizing only a narrowly defined sponsored operation. ### Attack Path 1. The attacker obtains the p ...[truncated 1400 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions Do not sign arbitrary serialized transactions received from clients. Prefer having the client submit a structured transaction intent and reconstruct the transaction on the server from validated fields. At minimum: 1. Require authenticated requests and verify that the caller is authorized to receive sponsorship. 2. Parse and validate every transaction instruction before signing. 3. Require the transaction fee payer to exactly match the configured sponsorship wallet. 4. Allowlist permitted Solana program IDs and instruction types. 5. Validate every writable account, signer, source, destination, amount, and token mint. 6. Explicitly reject instructions that transfer, close, assign, delegate, or otherwise modify assets owned by the fee-payer account. 7. Reject unexpected address lookup tables and unsupported transaction versions. 8. Enforce recent blockhash validity and prevent replay. 9. Apply strict request-body and serialized-transaction size limits. 10. Add per-user, per-session, per-IP, and global rate limits. 11. Enforce per-transaction and cumulative sponsorship budgets. 12. Simulate the transaction and inspect balance changes before signing. 13. Use a dedicated low-balance fee-payer wallet with no unrelated assets. 14. Log all sponsorship decisions and alert on unusual recipients, programs, or spending patterns. ]]>
