T09 · Insecure Skill Coding Practices
- Location
src/client.ts:92- Finding
Unvalidated Result URL Enables Client-Side SSRF and Unbounded Downloads
- Content
View full analysis
{ const response = await axios.get(url, { responseType: 'stream' }); await fs.ensureDir(path.dirname(outputPath)); response.data.pipe(fs.createWriteStream(outputPath)); await new Promise((resolve, reject) => { response.data.on('end', resolve); response.data.on('error', reject); }); } ``` The URL passed to this method is obtained from the remote task-status response: ```ts if (!status.data.res_url) { throw new Error('No result URL in status response'); } console.log(`Downloading to ${outputPath}...`); await this.downloadResult(status.data.res_url, outputPath); ``` ### Technical Analysis The application treats the API-provided `res_url` as trusted and passes it directly to the global Axios client. It does not validate: - The URL scheme, such as requiring HTTPS. - The destination hostname against an allowlist of approved HitPaw CDN domains. - Whether the resolved address is loopback, link-local, private, or otherwise locally reachable. - Redirect destinations followed by Axios. - The response content type. - The response `Content-Length` or the number of bytes actually streamed. - A download-specific timeout. Consequently, a compromised or malicious status response can direct the client to make a GET request to an internal service, loopback interface, cloud metadata endpoint, or attacker-controlled redirect chain. This is a client-side SSRF condition. Although the implementation writes the response locally rather than explicitly returning it to the party controlling the URL, requests may still reach sensitive internal endpoints or trigger state-changing behavior on services that improperly accept GET requests. The absence of a maximum response ...[truncated 1916 chars]- Remediation
View remediation
