T09 · Insecure Skill Coding Practices
Error
- Location
- scripts/utils/validator.js:3
- Finding
- Unrestricted URL Fetching Can Exfiltrate Internal Resources Through Automatic Cloud Upload<![CDATA[ ## Vulnerability Details **File Location**: `scripts/utils/validator.js:3-9`, `scripts/video2text/index.js:97-107`, `scripts/video2text/index.js:140-149`, and `scripts/utils/download.js:478-493` **Vulnerability Type**: Server-Side Request Forgery and unintended data disclosure **Risk Level**: High ### Vulnerable Code ```js function isUrl(url) { try { const parsedUrl = new URL(url); return parsedUrl.protocol === "http:" || parsedUrl.protocol === "https:"; } catch (_) { return false; } } ``` ```js if (validator.isUrl(file)) { const filepath = utils.downloadPath(); try { await fs.promises.mkdir(filepath, { recursive: true }); } catch (error) { utils.printError("Temporary download directory creation failed: " + (error.message || String(error))); process.exit(1); } try { const downloadResult = await helper.download(file, filepath); ``` ```js const presignedUrl = await video.getPresignedUrl(tokenValue, file); if (!presignedUrl || !presignedUrl?.url || presignedUrl.url === "") { throw new Error("Failed to obtain a presigned URL"); } utils.printInfo("Uploading file..."); await upload.uploadFileToOSS(file, presignedUrl.url, presignedUrl.headers); utils.printInfo("File upload completed"); ``` ```js 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(redirectedURL); this.emit("redirected", redirectedURL, this.url); return this.__start(); } ``` ### Technical Analysis The URL validator only verifies that the supplied value uses the HTTP or HTTPS scheme. It does not reject loopba ...[truncated 2296 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Resolve destination hostnames before connecting and reject: - IPv4 and IPv6 loopback addresses. - RFC1918 private networks. - Link-local and unique-local ranges. - Multicast and unspecified addresses. - Known cloud metadata destinations. 2. Apply the same validation after every redirect, not only to the initial URL. 3. Protect against DNS rebinding by connecting only to the validated resolved address and verifying the address again when connections are established. 4. Permit HTTPS only unless HTTP is explicitly required and approved. 5. Reject redirects that downgrade from HTTPS to HTTP. 6. Introduce an allowlist of supported media domains where operationally possible. 7. Verify response MIME types and media file signatures before upload. 8. Require explicit confirmation before uploading content fetched from an untrusted or non-public destination. 9. Restrict presigned upload destinations to documented storage hostnames or hostname suffixes, and allow only the minimum required upload headers. 10. Consider network-level egress controls that prevent the process from reaching metadata and private-network ranges. ]]>
