T09 · Insecure Skill Coding Practices
- Location
esim_api.py:190- Finding
Unvalidated Remote Payment Parameters Can Redirect or Alter USDC Transactions
- Content
View full analysis
Vulnerability Details
File Location:
esim_api.py:190-231
Vulnerability Type: Failure to validate security-critical payment parameters
Risk Level: HighVulnerable Code
python data = response.json() # Parse x402 response - find the "transfer" scheme accepts_list = data.get("accepts", []) accepts = None for scheme in accepts_list: if scheme.get("scheme") == "transfer": accepts = scheme break # Fallback to first scheme if transfer not found if accepts is None: accepts = accepts_list[0] if accepts_list else {} extra = accepts.get("extra", {}) amount_raw = accepts.get("amount", 0) if isinstance(amount_raw, str): amount_raw = int(amount_raw) # Get network info from response network = accepts.get("network", self.config["caip2"]) chain_id = accepts.get("extra", {}).get("chainId", self.config["chain_id"]) return PaymentRequired( nonce=extra.get("nonce", ""), amount_raw=amount_raw, amount_usdc=amount_raw / 1_000_000, pay_to=accepts.get("payTo", ""), asset=accepts.get("asset", ""), network=network, chain_id=chain_id, )The associated workflow in
SKILL.md:248-252explicitly directs the caller to use the remotely supplied recipient:markdown **Important**: Always use the `payTo` address from the 402 response. Never hardcode payment addresses.Technical Analysis
The client accepts the recipient address, payment amount, asset contract, network, chain ID, and nonce directly from the remote HTTP 402 response. It does not enforce that:
networkequals the configured CAIP-2 network.chain_idequals the configured Base Mainnet or Base Sepolia chain ID.assetequals the ...[truncated 2488 chars]
- Remediation
View remediation
Remediation Suggestions
- Require an explicit
transferscheme and reject the response if none is present. Remove the fallback to the first entry. - Validate
networkandchainIdagainst the selected entry inNETWORK_CONFIG; do not use remote values to override local network selection. - Compare
assetcase-insensitively with the configured USDC contract for the selected network. - Validate
payToandassetas 20-byte hexadecimal EVM addresses before presenting transaction instructions. - Parse USDC values with
Decimalor integer smallest units instead of binary floating-point arithmetic. - Bind the payment response to the selected package and prior quote. Require the 402 amount to exactly equal the user-confirmed amount.
- Validate the nonce format and ensure it belongs to the current purchase attempt.
- Reject missing, zero, negative, malformed, or unexpectedly large payment amounts.
- Require renewed user confirmation if any payment parameter differs from the previously displayed transaction details.
- Before signing, display and independently verify the final recipient, token contract, chain, and amount. Wallet policy should enforce spending limits and an allowlist where operationally possible.
- After payment, verify the transaction receipt, successful token transfer event, recipient, token contract, amount, and chain before submitting the transaction hash as proof.
- Require an explicit
