T09 · Insecure Skill Coding Practices
- Location
logic.ts:318- Finding
Server-Side Request Forgery Through Unrestricted Article URL Fetching
- Content
View full analysis
{ try { // Fetch from Zoomin API with proper headers to get JSON with full HTML const response = await fetch(url, { headers: { 'Accept': 'application/json', }, redirect: 'follow', }); ``` The tool definition exposes the URL directly to callers: ```ts export const servicenow_get_article: ToolDef = { name: 'servicenow_get_article', description: 'Fetch the full content of a ServiceNow documentation article', schema: z.object({ url: z.string().describe('The article URL from search results'), }), execute: async (args: unknown) => { const { url } = args as { url: string }; return getArticle(url); }, }; ``` ### Technical Analysis The `servicenow_get_article` tool accepts an arbitrary string as its `url` argument and passes it directly to the server-side `fetch` API. The implementation does not: - Parse and validate the supplied URL. - Require the HTTPS protocol. - Restrict requests to approved ServiceNow hostnames. - Reject localhost, private, link-local, loopback, or reserved network addresses. - Restrict destination ports. - Resolve and validate destination IP addresses. - Validate redirect destinations. The request explicitly uses `redirect: 'follow'`. Consequently, even validation of only the initial hostname would remain vulnerable if an approved or attacker-controlled endpoint redirected the request to an internal destination. The `toPublicUrl()` helper does not mitigate this vulnerability because it is only used when formatting returned output. It neither validates nor transforms the URL before the network request occurs. ### Attack Path 1. An attacker or untrusted prompt invokes `servicenow_get_article` with a URL targeting an intern ...[truncated 1424 chars]- Remediation
View remediation
