T09 · Insecure Skill Coding Practices
Error
- Location
- x402.md:65
- Finding
- Unvalidated Server-Directed Cryptocurrency Payment Authorization<![CDATA[ ## Vulnerability Details **File Location**: `x402.md`, lines 65–77 and 151–179 **Vulnerability Type**: Unvalidated remote payment parameters and automatic wallet-backed payment signing **Risk Level**: High ### Vulnerable Code The payment challenge contains security-critical parameters controlled by the remote service: ```json { "scheme": "exact", "network": "eip155:8453", "maxAmountRequired": "10000", "resource": "https://api.hlprivateer.xyz/v1/agent/positions", "description": "Current open positions with symbols, sides, sizes, entries, PnL", "mimeType": "application/json", "payTo": "0x...", "maxTimeoutSeconds": 300, "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", "extra": { "name": "HL Privateer", "facilitator": "https://facilitator.payai.network" } } ``` The TypeScript example then gives a wallet-backed x402 client authority to process the remote payment flow without demonstrating validation, spending limits, or user confirmation: ```typescript import { x402Client } from "@x402/client"; import { createWalletClient, http } from "viem"; import { base } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; const account = privateKeyToAccount("0x<your-private-key>"); const wallet = createWalletClient({ account, chain: base, transport: http() }); const client = new x402Client(wallet); const response = await client.fetch( "https://api.hlprivateer.xyz/v1/agent/positions" ); const data = await response.json(); ``` ### Technical Analysis The documented x402 flow requires the client to sign a cryptocurrency authorization derived from a server-provided challenge. Fields such as `network`, `asset`, `resource`, `payTo`, `maxAmountRequired`, and expiration constraints determine what asset can be transferred, to whom, for what amount, and for how long the authorization remains usable. The guide does not require the client to verify these values against a local policy before signing. In part ...[truncated 2451 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Validate every challenge locally before signing** - Require `network` to equal `eip155:8453`. - Require `asset` to equal the canonical Base USDC contract: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`. - Require `resource` to use HTTPS and match the intended `api.hlprivateer.xyz` origin and requested path. - Verify that `payTo` belongs to a locally configured recipient allowlist rather than trusting the challenge alone. - Reject unknown schemes, facilitators, token contracts, recipients, and resources. 2. **Enforce strict financial limits** - Define an exact expected price for each route. - Reject any amount above the locally configured route price. - Add per-request, hourly, daily, and session-wide spending limits. - Disable automatic retries that can generate duplicate or repeated charges. 3. **Constrain authorization lifetime and replay potential** - Require a short `validBefore` interval. - Validate `validAfter`, nonce format, and nonce uniqueness. - Ensure the authorization is bound to the intended payment recipient, amount, asset, chain, and request. - Record consumed nonces and settlement transaction hashes where supported. 4. **Require informed approval** - Display the recipient, asset, chain, amount, resource, and expiration before signing. - Require explicit user confirmation unless the request falls within a separately approved, tightly bounded policy. - Clearly distinguish free endpoints from paid endpoints before initiating the payment flow. 5. **Use a least-privilege wallet** - Use a dedicated wallet funded only with the maximum acceptable spending budget. - Do not use a primary wallet or a wallet holding unrelated assets. - Avoid embedding private keys in source code or string literals; use a secure signer, hardware wallet, or protected secret store. 6. **Harden the example implementation** - Add explicit challenge-validation code before cal ...[truncated 197 chars]
