T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/utils/validator.js:3
- Finding
- Unrestricted URL Downloads Permit Server-Side Request Forgery and Disk Exhaustion<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:3-8`; `scripts/utils/download.js:317-331`, `464-492`, and `526-547` **Vulnerability Type**: Server-Side Request Forgery (SSRF) and uncontrolled resource consumption **Risk Level**: High ### Vulnerable Code ```javascript // scripts/utils/validator.js:3-8 function isUrl(url) { try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch (_) { return false; } } ``` ```javascript // scripts/utils/download.js:317-331 const req = this.__protocol.request(options, (response) => { if (this.__isRequireRedirect(response)) { redirectCount++; if (redirectCount > this.__opts.maxRedirects) { const err = new Error("Too many redirects"); this.__setState(this.__states.FAILED); this.emit("error", err); return reject(err); } const redirectedURL = /^https?:\/\//.test(response.headers.location) ? response.headers.location : new URL(response.headers.location, url).href; this.emit("redirected", redirectedURL, url); return getRequest(redirectedURL, getReqOptions(redirectedURL)); } ``` ```javascript // scripts/utils/download.js:464-492 return this.__protocol.request(this.__reqOptions, (response) => { this.__response = response; if (!this.__isResumed) { this.__total = parseInt(response.headers["content-length"]) || null; this.__resetStats(); } if (this.__isRequireRedirect(response)) { this.__redirectCount++; if (this.__redirectCount > this.__opts.maxRedirects) { const err = new Error("Too many redirects"); this.__setState(this.__states.FAILED); this.emit("error", err); return reject(err); } const redirectedURL = /^https?:\/\//.test(response.headers.location) ? response.headers.location : new URL(response.headers.location, this.url).href; this.__isRedirected = true; this.__initProtocol(r ...[truncated 3561 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Resolve every initial and redirected hostname before connecting. 2. Reject IPv4 and IPv6 loopback, private, link-local, multicast, unspecified, reserved, and cloud metadata address ranges. 3. Repeat destination validation after every redirect. 4. Pin the validated address for the actual connection or verify the connected socket address to mitigate DNS rebinding. 5. Prefer HTTPS and consider an allowlist of approved public video platforms where operationally feasible. 6. Reject URLs containing embedded credentials and restrict nonstandard ports if they are unnecessary. 7. Set a maximum download size and terminate the request as soon as either: - The declared `Content-Length` exceeds the limit, or - The number of streamed bytes exceeds the limit. 8. Apply connection, idle, and total download-duration timeouts. 9. Validate content type, file signatures, and supported video formats before uploading. 10. Delete partially downloaded files on every failure or limit violation. ]]>
