T09 · Insecure Skill Coding Practices
Error
- Location
- src/runtime.ts:79
- Finding
- Unrestricted outbound requests enable server-side request forgery and automatic payment abuse<![CDATA[ ## Vulnerability Details **File Location**: `src/runtime.ts:79-100`; related schema: `src/schemas.ts:37-58` **Vulnerability Type**: Server-Side Request Forgery (SSRF) and unsafe automatic payment handling **Risk Level**: High ### Vulnerable Code ```ts const fetchOptions: RequestInit & { autoPayment: boolean; maxRetries?: number; serviceId?: string; pricePerCall?: string; } = { method: params.method, headers: { "Content-Type": "application/json", ...(params.headers || {}), }, autoPayment: true, }; // Pass on-chain serviceId and pricePerCall to SDK for validation (mismatch throws error) if (params.serviceId) { fetchOptions.serviceId = params.serviceId; } if (params.pricePerCall) { fetchOptions.pricePerCall = params.pricePerCall; } if (params.body) { fetchOptions.body = JSON.stringify(params.body); } const response = await this.client.fetch(params.url, fetchOptions); ``` The corresponding tool schema accepts an unrestricted string: ```ts url: { type: "string", description: "AI service endpoint URL", }, method: { type: "string", enum: ["GET", "POST", "PUT", "DELETE"], description: "HTTP method (default: POST)", }, body: { type: "object", description: "Request body (will be JSON-serialized)", }, headers: { type: "object", description: "Additional HTTP headers", additionalProperties: { type: "string" }, }, ``` ### Technical Analysis `params.url` is supplied by the tool caller and passed directly to `client.fetch`. The implementation does not: - Require HTTPS. - Restrict destinations to trusted service-registry endpoints. - Reject loopback, private, link-local, multicast, or reserved IP ranges. - Protect cloud metadata endpoints. - Resolve and validate hostnames against DNS rebinding. - Revalidate redirect destinations. - Restrict sensitive caller-controlled request headers. The request also sets `autoPayment: true`. Consequently, the same primitive that performs an unrestricted outbound request ca ...[truncated 1607 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only `https:` URLs in production. 2. Bind paid requests to endpoints retrieved from a trusted and verified on-chain registry. 3. Resolve destination hostnames before connecting and reject: - Loopback addresses. - RFC 1918 private networks. - Link-local addresses. - Carrier-grade NAT ranges. - Multicast and reserved ranges. - IPv6 local, link-local, and IPv4-mapped private addresses. 4. Disable redirects or repeat full URL and IP validation after every redirect. 5. Protect against DNS rebinding by connecting only to the validated resolved address while preserving correct TLS hostname verification. 6. Remove arbitrary header support or allowlist harmless headers. Explicitly reject `Authorization`, `Cookie`, `Host`, proxy headers, and internal authentication headers. 7. Require `serviceId`, expected price, expected chain ID, and expected endpoint for every automatic payment. 8. Introduce strict timeouts, response-size limits, retry limits, and outbound network egress controls. 9. Separate an unpaid discovery request from payment execution and require explicit authorization before signing a transaction. ]]>
