T09 · Insecure Skill Coding Practices
- Location
- mya.py:1442
- Finding
- Server-Controlled Financial Transactions Are Signed Without Semantic Validation<![CDATA[ ## Vulnerability Details **File Location**: `mya.py:1442-1452`, `mya.py:2673-2681`, `mya.py:3552-3562`, `mya.py:3709-3717`, `mya.py:4177-4192`, `mya.py:4269-4284`, `mya.py:4441-4453` **Vulnerability Type**: Insufficient validation of remotely supplied transactions before signing **Risk Level**: Critical ### Vulnerable Code ```python def verify_transaction(tx_bytes: bytes, expected_signer: str) -> bool: try: tx = SoldersTransaction.from_bytes(tx_bytes) message = tx.message if not message.recent_blockhash or message.recent_blockhash == Hash.default(): Output.error("Transaction missing blockhash") return False if not any(str(acc) == expected_signer for acc in message.account_keys): Output.error("Transaction missing signer") return False return True except Exception as e: Output.error("Transaction verification failed") log_error(f"TX verify: {e}") return False ``` The launch workflow signs the remotely returned transaction after applying only the weak check above: ```python tx_bytes = base64.b64decode(prepare_result.data["transaction"]) mint_address = prepare_result.data["mintAddress"] if not verify_transaction(tx_bytes, creator_address): Output.error("Transaction verification failed") sys.exit(ExitCode.SECURITY_ERROR) tx = SoldersTransaction.from_bytes(tx_bytes) tx.sign([keypair], tx.message.recent_blockhash) signed_tx_b64 = base64.b64encode(bytes(tx)).decode() ``` Poker escrow workflows do not perform even this limited validation: ```python if escrow and escrow.get('unsignedTx'): print("Signing escrow deposit transaction...") try: tx_bytes = base64.b64decode(escrow['unsignedTx']) tx = SoldersTransaction.from_bytes(tx_bytes) signed_tx = wallet.sign_transaction(tx) signed_b64 = base64.b64encode(bytes(signed_tx)).decode('utf-8') with Spinner("Confirming on-chain deposit..."): ...[truncated 3224 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Prefer constructing all financial transactions locally from reviewed instruction builders. 2. If remote transaction construction is unavoidable, decode every instruction before signing and enforce an operation-specific allowlist. 3. For token launches, verify: - Exact program IDs and instruction discriminators. - Expected creator, mint, treasury, pump.fun, token, and metadata accounts. - Exact platform fee and maximum initial-buy amount. - Fee payer and required signer positions. - Absence of unexpected transfers, delegates, account closures, or authority changes. 4. For poker deposits, independently derive and verify the escrow PDA, game identifier, recipient, program ID, and exact buy-in amount. 5. Compute the transaction's maximum wallet debit and reject anything above the confirmed amount plus a narrowly bounded network fee. 6. Display a decoded transaction summary and require confirmation immediately before signing. 7. Do not treat the wallet's mere presence in `account_keys` as proof that a transaction is safe. 8. Add adversarial tests using transactions containing extra transfer, delegate, authority-change, and account-close instructions. ]]>
