T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/quick-bridge.sh:135
- Finding
- Unvalidated Remote Transaction Payload Is Signed with the User's Private Key<![CDATA[ ## Vulnerability Details **File Location**: `scripts/quick-bridge.sh`, lines 135–149 and 174–183 **Vulnerability Type**: Unvalidated signing of remotely supplied blockchain transaction data **Risk Level**: High ### Vulnerable Code ```bash CONVERTED_AMOUNT=$(echo "$AMOUNT * 10^18" | bc | cut -d'.' -f1) QUOTE=$(curl -s -X POST "https://api.relay.link/quote/v2" \ -H "Content-Type: application/json" \ -d "{ \"user\": \"$USER_ADDR\", \"originChainId\": $ORIGIN_ID, \"destinationChainId\": $DEST_ID, \"originCurrency\": \"$ORIGIN_CURR\", \"destinationCurrency\": \"$DEST_CURR\", \"recipient\": \"$DEST_ADDR\", \"amount\": \"$CONVERTED_AMOUNT\", \"tradeType\": \"EXACT_INPUT\" }") ``` ```bash read -p "Do you want to sign and send this transaction now? (yes/no): " CONFIRM if [ "$CONFIRM" == "yes" ]; then echo "🚀 Sending transaction..." TX_TO=$(echo "$QUOTE" | jq -r '.steps[0].items[0].data.to') TX_VALUE=$(echo "$QUOTE" | jq -r '.steps[0].items[0].data.value') TX_DATA=$(echo "$QUOTE" | jq -r '.steps[0].items[0].data.data') # Use environment variable for private key instead of CLI arg for security export ETH_PRIVATE_KEY="$EVM_PRIVATE_KEY" RESULT=$(cast send "$TX_TO" "$TX_DATA" --value "$TX_VALUE" --rpc-url "$RPC_URL_AVAX" 2>&1) ``` The RPC endpoint is also fixed to Avalanche regardless of the selected origin chain: ```bash RPC_URL_AVAX="https://api.avax.network/ext/bc/C/rpc" ``` ### Technical Analysis The script treats the Relay quote API response as trusted transaction authorization data. The remote response directly controls: - The transaction recipient through `.data.to` - The native currency amount through `.data.value` - The contract call and its arguments through `.data.data` These values are passed directly to `cast send`, which signs the transaction using the private key loaded from `EVM_PRIVATE_KEY`. The script does not validate the destinati ...[truncated 3013 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Verify the active chain before signing** - Map each supported origin chain to an approved RPC endpoint. - Query the RPC chain ID immediately before signing. - Abort unless it exactly matches `originChainId`. - Do not silently route every transaction through Avalanche. 2. **Validate every transaction field** - Require `to`, `value`, and `data` to exist and have valid formats. - Reject `null`, empty, malformed, or unexpected fields. - Enforce a maximum native value derived from the user's requested amount and an explicit fee allowance. - Maintain an allowlist of official bridge/router contracts for each chain. - Reject transaction targets that are not approved for the selected route. 3. **Decode and constrain calldata** - Decode the function selector and arguments before signing. - Permit only expected bridge, transfer, and approval methods. - For token approvals, verify the spender and cap the approval to the amount required for the current transaction. - Reject unlimited approvals unless separately and explicitly authorized. 4. **Provide meaningful confirmation** - Display the origin chain and verified RPC chain ID. - Display the target contract, native value, decoded operation, token amount, spender, approval amount, fees, slippage, and recipient. - Require confirmation only after all fields that will be signed have been shown. - Ensure that the transaction fields displayed are the exact immutable fields subsequently passed to `cast send`. 5. **Handle token precision correctly** - Obtain token decimals from trusted chain metadata or an on-chain contract query. - Validate that the requested currency belongs to the selected origin chain. - Convert the human-readable amount using the verified token precision instead of always using 18 decimals. 6. **Fail closed** - Enable strict shell behavior such as `set -euo pipefail`. - Use `curl --fail --show-error` w ...[truncated 500 chars]
