T09 · Insecure Skill Coding Practices
- Location
SKILL.md:121- Finding
Unvalidated Server-Directed Cryptocurrency Payment
- Content
View full analysis
Vulnerability Details
File Location:
SKILL.md, lines 121-124 and 140-161
Vulnerability Type: Unvalidated payment authorization to an environment-controlled endpoint
Risk Level: HighVulnerable Code
ts const baseUrl = process.env.X402_API_BASE_URL ?? process.env.API_BASE_URL ?? "https://www.x402api.app/"; const endpoint = `${baseUrl.replace(/\/$/, "")}/api/v1/qrcode/generate`;ts const unpaid = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload), }); if (unpaid.status !== 402) { const unpaidBody = await unpaid.text(); throw new Error(`Expected unpaid status 402, got ${unpaid.status}. body=${unpaidBody}`); } const paymentRequired = httpClient.getPaymentRequiredResponse( (name) => unpaid.headers.get(name), {}, ); const paymentPayload = await httpClient.createPaymentPayload(paymentRequired); const response = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json", ...httpClient.encodePaymentSignatureHeader(paymentPayload), }, body: JSON.stringify(payload), });Technical Analysis
The client permits
X402_API_BASE_URLorAPI_BASE_URLto determine the service origin. It then accepts payment requirements from that origin and passes them directly tocreatePaymentPayload. The example performs no explicit validation of the expected network, payment scheme, asset, recipient, amount, expiration, or API origin before authorizing the payment.An HTTP
402 Payment Requiredstatus establishes only that the remote server returned the expected status code; it does not establish that the requested payment is legitimate or within the user's intended spending limits. If the environment configuration is modified or the configured service is compromised, the responding server can supply attacker-selected payment requirements....[truncated 1419 chars]
- Remediation
View remediation
Remediation Suggestions
- Pin the API to an exact HTTPS origin or enforce a strict hostname and port allowlist. Do not accept arbitrary environment-provided origins without validation.
- Reject URL credentials, non-HTTPS protocols, unexpected ports, and origins whose normalized hostname does not exactly match the approved service.
- Disable redirects or verify that every redirect target and the final response origin remain allowlisted.
- Before signing, validate the payment network and chain ID, scheme, asset or token contract, recipient address, amount, expiration, and request association against locally configured expectations.
- Enforce strict per-request, per-session, and cumulative spending caps.
- Require explicit user confirmation when the recipient changes, the asset changes, or the requested amount exceeds a low predefined threshold.
- Bind the payment authorization to the intended method, endpoint, payload, and trusted origin where supported by the protocol.
- Use a dedicated, low-balance wallet with narrowly scoped allowances rather than a primary wallet.
- Record payment destination, asset, amount, network, and request identifier in security logs without logging the private key or reusable sensitive authorization material.
- Add negative tests covering malicious 402 responses, excessive amounts, unexpected recipients, unsupported networks, redirects, malformed requirements, and attacker-controlled base URLs.
