T09 · Insecure Skill Coding Practices
Warning
- Location
- scripts/lib/providers.mjs:23
- Finding
- Unrestricted Remote URL Fetching Enables Server-Side Request Forgery<![CDATA[ ## Vulnerability Details **File Location**: `scripts/lib/providers.mjs:23-43`, `scripts/lib/providers.mjs:147-151`, and `scripts/gen.mjs:220-233` **Vulnerability Type**: Server-Side Request Forgery and unbounded remote content retrieval **Risk Level**: Medium ### Vulnerable Code ```js const isUrl = (s) => /^https?:\/\//i.test(s) const MIME = { '.jpg': 'image/jpeg', '.jpeg': 'image/jpeg', '.png': 'image/png', '.webp': 'image/webp', '.gif': 'image/gif', } const mimeOf = (p) => MIME[path.extname(p).toLowerCase()] || 'image/jpeg' async function asBase64(p) { if (isUrl(p)) { const r = await fetch(p) if (!r.ok) throw new Error(`拉取参考图失败 ${r.status}: ${p}`) return Buffer.from(await r.arrayBuffer()).toString('base64') } return (await readFile(p)).toString('base64') } const asDataUri = async (p) => isUrl(p) ? p : `data:${mimeOf(p)};base64,${await asBase64(p)}` ``` The OpenAI provider independently retrieves user-supplied image URLs: ```js for (const p of req.images) { const buf = isUrl(p) ? Buffer.from(await (await fetch(p)).arrayBuffer()) : await readFile(p) fd.append('image[]', new Blob([buf], { type: mimeOf(p) }), path.basename(p)) } ``` Provider-returned output URLs are also downloaded without destination validation: ```js async function persist(files, savePath, req) { if (!files?.length) return [] const out = [] for (const [i, f] of files.entries()) { let target if (savePath) { const ext = path.extname(savePath) || f.ext || '.jpg' const base = savePath.slice(0, savePath.length - path.extname(savePath).length) target = files.length > 1 ? `${base}-${i + 1}${ext}` : `${base}${ext}` } else { target = path.join('output', `${Date.now()}-${i + 1}${f.ext || '.jpg'}`) } await mkdir(path.dirname(target), { recursive: true }) const buf = f.buffer || Buffer.from(await (await fetch(f.url)).arrayBuffer()) await writeFile(target, buf) out.push(target) } return o ...[truncated 2746 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Default to accepting local reference files only. 2. Require an explicit option, such as `--allow-remote-images`, before fetching remote images. 3. If remote images are necessary, enforce an allowlist of trusted HTTPS hostnames. 4. Resolve the target hostname before every request and reject: - Loopback addresses. - Link-local addresses. - Private IPv4 and IPv6 ranges. - Multicast and reserved ranges. - Cloud metadata addresses. 5. Disable redirects or validate the hostname and resolved address after every redirect. 6. Reject redirects that change from HTTPS to HTTP. 7. Apply strict connection and response timeouts. 8. Stream responses while enforcing a maximum byte count instead of calling `arrayBuffer()` without a limit. 9. Validate `Content-Type` and inspect file signatures before treating a response as media. 10. Apply the same URL validation policy to provider-returned output URLs. 11. Consider requiring provider output URLs to match documented provider-owned domains. 12. Avoid forwarding remotely fetched content to cloud providers unless the user is clearly informed and has approved that transfer. ]]>
