T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/x402-fetch.mjs:41
- Finding
- Automatic payment signing lacks destination and spending restrictions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/x402-fetch.mjs:41-91` **Vulnerability Type**: Unrestricted automatic payment authorization **Risk Level**: High ### Vulnerable Code ```js const url = args[0]; ``` ```js // Create signer and x402 client const signer = privateKeyToAccount(privateKey); if (!quiet) console.error(`Wallet: ${signer.address}`); const client = new x402Client(); registerExactEvmScheme(client, { signer }); const fetchWithPayment = wrapFetchWithPayment(fetch, client); // Make the request const fetchOpts = { method, headers }; if (body) fetchOpts.body = body; if (!quiet) console.error(`${method} ${url}`); try { const response = await fetchWithPayment(url, fetchOpts); ``` ### Technical Analysis The script accepts an arbitrary user-supplied URL and passes it to a payment-enabled fetch wrapper backed by a wallet signer. It does not locally enforce: - HTTPS-only transport - A trusted destination or payee allowlist - An expected blockchain network - An expected payment asset - A maximum payment amount - A cumulative spending limit - Interactive confirmation before signing Signing payment authorizations is necessary for the declared x402 functionality, but automatically granting this capability to any supplied endpoint exceeds safe minimum privilege. A malicious, compromised, or incorrectly configured server can return x402 payment requirements that the wrapper may process without explicit user review. The code does not transmit the raw private key directly. It does, however, provide the SDK with signing authority and sends the resulting signed payment authorization as part of the x402 exchange. ### Attack Path 1. An attacker persuades an operator or agent to invoke the script with an attacker-controlled URL, or compromises a previously trusted endpoint. 2. The endpoint responds with crafted x402 payment requirements. 3. `wrapFetchWithPayment` processes the response using the registered EVM signer. 4. Because the scrip ...[truncated 843 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Reject all non-HTTPS URLs before making a request. 2. Maintain an explicit allowlist of trusted hostnames or require a deliberate override for unknown hosts. 3. Decode and validate every payment requirement before signing, including: - Chain identifier - Payment asset and contract address - Recipient/payee address - Per-request amount - Expiration and replay-related fields 4. Add a secure default maximum payment amount and a cumulative session spending cap. 5. Display the normalized payment terms and require interactive confirmation unless the endpoint and limits were explicitly preapproved. 6. Fail closed when payment requirements contain unsupported or ambiguous fields. 7. Use a dedicated low-balance wallet for automated requests. 8. Document that endpoint health checks do not establish the identity or trustworthiness of the payment recipient. ]]>
