T09 · Insecure Skill Coding Practices
- Location
scripts/sign-and-send.js:29- Finding
Untrusted Gateway Transactions Are Signed Without Instruction Validation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/sign-and-send.js:29-48
Vulnerability Type: Blind signing of externally supplied blockchain transactions
Risk Level: HighVulnerable Code
js const res = JSON.parse(readFileSync(responsePath, 'utf8')); const secret = Uint8Array.from(JSON.parse(readFileSync(keypairPath, 'utf8'))); const keypair = Keypair.fromSecretKey(secret); if (res.sender && keypair.publicKey.toBase58() !== res.sender) { console.error(`Keypair ${keypair.publicKey.toBase58()} does not match sender ${res.sender}`); process.exit(1); } const connection = new Connection( rpcUrl || 'https://api.mainnet-beta.solana.com', 'confirmed', ); console.log(`Signing ${res.transactionCount} transaction(s) as ${keypair.publicKey.toBase58()}`); for (const [i, b64] of res.transactions.entries()) { const tx = Transaction.from(Buffer.from(b64, 'base64')); tx.sign(keypair); try { const sig = await connection.sendRawTransaction(tx.serialize());Technical Analysis
The helper treats every serialized transaction in an external response file as trusted. It deserializes, signs, and broadcasts each transaction without inspecting its instructions or confirming that they match the user's intended payment operation.
The existing sender check is insufficient because:
res.senderis optional; the check is skipped if that response field is absent.- The check validates response metadata rather than the serialized transaction's fee payer and required signers.
- It does not validate recipients, transfer amounts, token mint, fee recipient, fee amount, program IDs, or additional instructions.
- It does not bind the transaction to a locally retained copy of the original request.
- It does not reject unknown or dangerous program instructions.
Solana transaction signatures authorize the serialized message, not the human-readable response metadata. Therefore, ...[truncated 1682 chars]
- Remediation
View remediation
Remediation Suggestions
Implement fail-closed transaction verification before signing:
- Require
res.senderand reject responses where it is missing. - Verify the serialized transaction's fee payer and required signer set directly.
- Retain the original local request and compare every transaction instruction against it.
- Decode and validate all recipient addresses, transfer amounts, token mints, associated-token-account creation instructions, and service fees.
- Allow only explicitly approved Solana program IDs and instruction types.
- Reject unknown, additional, duplicated, or reordered instructions that are not expected by the validated transaction model.
- Verify that the transaction blockhash matches the expected response and is current.
- Independently calculate totals across all transaction chunks and ensure they match the user's approved batch.
- Display a deterministic transaction summary, including recipients, assets, totals, fees, and program IDs.
- Require explicit user confirmation after validation and before signing or broadcasting.
- Where practical, simulate the transaction through a trusted RPC and inspect the simulation result before requesting approval.
- Add adversarial tests covering omitted sender metadata, extra instructions, altered recipients, excessive fees, unknown programs, and mismatched mints.
- Require
