T09 · Insecure Skill Coding Practices
- Location
index.js:6- Finding
Server-Side Request Forgery Through Unrestricted User-Supplied URLs
- Content
View full analysis
(.*?)<\/title>/i); return titleMatch ? titleMatch[1].trim() : null; } catch (e) { return null; } } ``` The user-controlled value reaches both request functions without validation: ```js const { url, fact } = args; // Check URL accessibility let checkResult = null; if (url) { try { const result = await checkUrlAccessibility(url); const title = await getPageTitle(url); checkResult = { url, accessible: result.accessible, statusCode: result.status, title }; } catch (e) { checkResult = { url, accessible: false, error: e.message }; } } ``` ### Technical Analysis The `url` property is accepted directly from `args` and passed to `fetch()` twice. The implementation does not restrict URL schemes, destinations, resolved IP addresses, ports, or redirects. In particular, it does not reject loopback, private, link-local, reserved, or cloud metadata addresses. This creates an SSRF primitive in which an attacker can cause the host running the skill to send HEAD and GET requests to network resources reachable from that host. Redirects are also not validated, so validation limited only to an initial hostname would remain bypassable unless every redirect destination is checked. The returned status code, accessibility result, and extracted page title provide an observable response channel. Although the implementation does not return the complete response body, ...[truncated 1562 chars]- Remediation
View remediation
