T09 · Insecure Skill Coding Practices
- Location
index.js:221- Finding
Server-Side Request Forgery and Domain-Policy Redirect Bypass
- Content
View full analysis
allowlist > default if (allowlist.size > 0) return allowlist.has(host); return true; } ``` ```js async function fetchWithRetry(url, options, retries, debug) { let lastErr; for (let i = 0; i <= retries; i++) { const controller = new AbortController(); const timer = setTimeout(() => controller.abort(), options.timeoutMs); try { const res = await _fetch(url, { headers: options.headers, signal: controller.signal, redirect: 'follow' }); clearTimeout(timer); return res; ``` ```js try { const u = new URL(url); if (!domainAllowed(u.hostname)) throw new Error(`Domain blocked by policy: ${u.hostname}`); const markdownEnabled = !DISABLE_MARKDOWN_ENV && options.markdown !== false; // env disable has highest priority const timeoutMs = Number(options.timeout || DEFAULT_TIMEOUT_MS); ``` ### Technical Analysis The command accepts a caller-controlled URL and sends a request using the runtime's network privileges. When no allowlist is configured, `domainAllowed()` permits every hostname except exact blocklist entries. It does not reject loopback, private, link-local, multicast, reserved, or cloud metadata addresses. Furthermore, the policy check is performed only against the hostname in the original URL. The request is then issued with `redirect: 'follow'`, allowing the HTTP client to follow redirects automatically without validating each redirect destination. A public or allowlisted host can therefore redirect the request to an internal or explicitly blocklisted destination. Exact hostname comparison is also insufficient to ...[truncated 2316 chars]- Remediation
View remediation
