T09 · Insecure Skill Coding Practices
Error
- Location
- lib/torchsdk/tokens.js:272
- Finding
- Unrestricted On-Chain Metadata Fetch Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `lib/torchsdk/tokens.js:272-276`; supporting fetch implementation at `lib/torchsdk/gateway.js:30-41` **Vulnerability Type**: Server-Side Request Forgery through attacker-influenced token metadata URI **Risk Level**: High ### Vulnerable Code ```js // lib/torchsdk/tokens.js:272-276 const uri = (0, program_1.decodeString)(bondingCurve.uri); if (uri) { try { const res = await (0, gateway_1.fetchWithFallback)(uri); const data = (await res.json()); ``` ```js // lib/torchsdk/gateway.js:30-41 const fetchWithFallback = async (url, options, timeoutMs = 10000) => { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), timeoutMs); const opts = { ...options, signal: controller.signal }; try { // If it's an Irys gateway URL, use uploader directly (gateway has SSL issues) if ((0, exports.isIrysUrl)(url)) { const uploaderUrl = (0, exports.irysToUploader)(url); return await fetch(uploaderUrl, opts); } // For non-Irys URLs, fetch normally return await fetch(url, opts); ``` ### Technical Analysis The `getToken()` implementation retrieves the metadata URI from on-chain bonding-curve state and passes it directly to `fetchWithFallback()`. The latter accepts arbitrary non-Irys URLs and calls `fetch()` without validating: - The URL scheme - The destination hostname - Resolved IP addresses - Loopback, private, link-local, or cloud metadata address ranges - Redirect destinations - Response content type - Maximum response size The bot invokes `getToken()` from `snapshotMarket()` for each active market. Consequently, metadata retrieval is part of normal continuous operation rather than an explicitly authorized metadata-fetching action. The local allowlist applied to pending market definitions does not fully mitigate this issue. Already-active market entries are not revalidated, and an allowl ...[truncated 1743 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Permit only `https:` metadata URLs. 2. Apply the approved-host allowlist immediately before every metadata request, including requests for already-active markets. 3. Resolve the hostname and reject all loopback, private, link-local, multicast, reserved, and cloud metadata address ranges for both IPv4 and IPv6. 4. Set `redirect: "manual"` and validate every redirect destination before following it. 5. Protect against DNS rebinding by connecting only to the validated resolved address or by using a hardened outbound proxy. 6. Enforce a strict response-size limit before parsing JSON. 7. Require an expected JSON content type and reject non-JSON responses. 8. Consider removing metadata retrieval from `getToken()` and exposing it as a separate, explicitly enabled operation. Market snapshots only require on-chain price, volume, holder, and treasury information. 9. Apply a restrictive outbound network policy so the process cannot contact localhost, private networks, or cloud metadata services. ]]>
