T09 · Insecure Skill Coding Practices
- Location
scripts/x402-generate.mjs:45- Finding
Automatic Cryptocurrency Payment Lacks Client-Side Authorization Limits
- Content
View full analysis
Vulnerability Details
File Location:
scripts/x402-generate.mjs, lines 45–71
Vulnerability Type: Unbounded automatic cryptocurrency payment authorization
Risk Level: HighVulnerable Code
js // --- Setup x402 payment-wrapped fetch --- let fetchWithPayment; try { const { wrapFetchWithPayment, x402Client } = await import('@x402/fetch'); const { registerExactEvmScheme } = await import('@x402/evm/exact/client'); const client = new x402Client(); registerExactEvmScheme(client, { signer }); fetchWithPayment = wrapFetchWithPayment(fetch, client); } catch { const { wrapFetchWithPayment } = await import('x402-fetch'); fetchWithPayment = wrapFetchWithPayment(fetch, signer); } // --- Generate --- console.log(`\n🎬 Generating video...`); console.log(` Prompt: "${prompt.slice(0, 80)}${prompt.length > 80 ? '...' : ''}"`); console.log(` Model: ${model}`); console.log(` Duration: ${duration}s`); if (agentId) console.log(` Agent: ${agentId}`); console.log(); const res = await fetchWithPayment(`${API_BASE}/generation/create`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, videoModel: model, duration, ...(agentId && { agentId }) }), });Technical Analysis
The script gives an x402 payment wrapper access to a signer derived from
EVM_PRIVATE_KEY. When the generation API returns HTTP402 Payment Required, the wrapper can sign the server-provided payment requirements and retry the request automatically.The script does not independently enforce:
- A maximum user-approved payment amount.
- The expected Base chain identifier.
- The expected USDC token contract.
- The expected payment receiver.
- The expected resource URL.
- An immutable quote tied to the prompt, model, and duration.
- A fresh explicit user confirmation before signing.
This behavior conflicts with the documented safeguard in
SKILL.md:173–201, which requires presenting the real quote and obta ...[truncated 1494 chars]- Remediation
View remediation
Remediation Suggestions
- Perform an unsigned request first and parse the
402 Payment Requiredresponse without invoking the automatic payment wrapper. - Validate every payment requirement locally:
- Chain must be Base mainnet (
eip155:8453). - Token must be the expected Base USDC contract.
- Receiver must match an explicit trusted allowlist.
- Resource must exactly match the intended generation endpoint.
- Amount must not exceed a user-approved maximum.
- Chain must be Base mainnet (
- Display the complete prompt, model, duration, agent ID, receiver, token, chain, and exact total.
- Require explicit confirmation after displaying the final quote.
- Bind the approval to a canonical hash of the request and payment requirements.
- Reject the transaction if any payment parameter changes between quotation and submission.
- Avoid broad automatic retry behavior after signing.
- Prefer a dedicated, low-balance wallet with only the funds required for the intended generation.
- Remove or strictly control the legacy
x402-fetchfallback so that all payment implementations apply identical validation policies. - Add automated tests confirming that excessive amounts, unexpected receivers, incorrect tokens, incorrect chains, and changed retry requirements are rejected.
- Perform an unsigned request first and parse the
