T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/fetch-with-payment.ts:44
- Finding
- Automatic Payment Requests Do Not Enforce a Mandatory Spending Limit or Destination Allowlist<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch-with-payment.ts:44-75` **Vulnerability Type**: Unrestricted payment destination and optional spending limit **Risk Level**: High ### Complete Code Snippet ```typescript // Build query parameters const params = new URLSearchParams(); params.set("url", options.url); params.set("method", options.method); if (options.from) { params.set("from", options.from); } if (options.maxValue) { params.set("maxValue", options.maxValue); } if (options.asset) { params.set("asset", options.asset); } if (options.chainId) { params.set("chainId", options.chainId); } const fetchUrl = `${THIRDWEB_API_BASE}/v1/payments/x402/fetch?${params.toString()}`; try { const response = await fetch(fetchUrl, { method: "POST", headers: { "Content-Type": "application/json", "x-secret-key": secretKey }, body: options.body ? JSON.stringify(options.body) : undefined }); ``` ### Technical Analysis The wrapper accepts an arbitrary target URL and forwards it to thirdweb's automatic x402 payment endpoint. The `maxValue` parameter is optional, so no local upper bound is applied when callers omit it. Although `assets/config-template.json` declares a default `maxPaymentUSD` value of `10.00`, the payment script does not read or enforce that configuration. The script also does not validate the target scheme, hostname, recipient, asset, chain, or requested payment amount before invoking the payment service. This is particularly risky in an agent environment because target URLs may originate from user input or service-discovery data. A malicious or compromised service can request a payment greater than the amount expected by the user. The code delegates the decision entirely to the remote payment service without an independent local policy or confirmation boundary. ### Attack Path 1. An attacker publishes or supplies an x402-compatible endpoint, potentially through a service catalog or untruste ...[truncated 893 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Make `maxValue` mandatory at the payment boundary and reject calls where it is absent, malformed, zero, negative, or above a locally configured ceiling. 2. Enforce a conservative local default rather than relying on caller behavior. 3. Define the limit in the token's smallest unit and validate it with integer arithmetic to avoid unit or floating-point errors. 4. Restrict targets to HTTPS and maintain an explicit allowlist of approved hostnames and paths. 5. Reject embedded credentials, nonstandard ports, redirects to unapproved hosts, and private or loopback destinations. 6. Validate the expected chain, token contract, recipient, and amount before authorizing payment. 7. Present the final payment amount, asset, network, recipient, and target service to the user and require confirmation for new services or amounts above a low threshold. 8. Add cumulative session and daily spending limits, not only per-request limits. 9. Connect the declared `maxPaymentUSD` or `X402_MAX_PAYMENT` setting to actual enforcement and add tests proving that missing or excessive limits are rejected. ]]>
