T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/audit.js:300
- Finding
- Server-Side Request Forgery Through Attacker-Controlled Agent URI## Vulnerability Details **File Location**: `scripts/audit.js`, lines 300–329; request helper at lines 155–171 **Vulnerability Type**: Unrestricted server-side request forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```js async function fetchJson(url, timeout = 10000) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); try { const response = await fetch(url, { signal: controller.signal }); clearTimeout(timeoutId); if (!response.ok) { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } return await response.json(); } catch (error) { clearTimeout(timeoutId); throw error; } } ``` ```js let agentURI; try { agentURI = await identityRegistry.tokenURI(agentId); report.metadata.agentURI = agentURI; console.log(` Agent URI: ${agentURI}`); } catch (error) { findings.push({ severity: SEVERITY.CRITICAL, title: 'Missing Agent URI', description: 'Could not retrieve agent URI from registry', recommendation: 'Contact agent owner to set agentURI' }); report.summary.critical++; console.log(` ${colors.red}✗ Error: ${error.message}${colors.reset}`); return report; } let registration; try { if (agentURI.startsWith('data:')) { const base64Data = agentURI.replace('data:application/json;base64,', ''); const jsonStr = Buffer.from(base64Data, 'base64').toString('utf-8'); registration = JSON.parse(jsonStr); } else { registration = await fetchJson(agentURI); } ``` ### Technical Analysis The agent owner controls the `tokenURI` returned by the on-chain registry. Every URI not beginning with `data:` is passed directly to the built-in `fetch` API. No validation is performed on: - The URI scheme. - The destination hostname. - The destination's resolved IPv4 or IPv6 addresses. - Lo ...[truncated 2131 chars]
- Remediation
- ## Remediation Suggestions 1. Allow only explicitly supported URI schemes, such as `https:` and strictly validated `data:application/json;base64`. 2. Implement IPFS access through a configured trusted gateway rather than passing `ipfs:` URIs to generic `fetch`. 3. Resolve destination hostnames before connecting and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 ranges. 4. Explicitly reject cloud metadata destinations, including link-local metadata addresses. 5. Disable automatic redirects or validate the scheme, hostname, and resolved address at every redirect. 6. Reject URLs containing embedded usernames or passwords. 7. Apply a strict response-size limit before parsing JSON. 8. Retain the timeout and add limits for redirect count and decompressed response size. 9. Consider routing metadata requests through an isolated egress proxy with no access to internal networks. 10. Validate the response content type and registration schema before adding it to the report.
