{"record":{"id":"dda7ac7708b55b15","repo":"ruvnet/ruflo","slug":"redirect-to-unsafe-url-blocked-ssrf","errorCode":null,"errorMessage":"Redirect to unsafe URL blocked (SSRF)","messagePattern":"Redirect to unsafe URL blocked \\(SSRF\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/routes/api/fetch-url/+server.ts","lineNumber":97,"sourceCode":"\t\t\t\t},\n\t\t\t});\n\n\t\t\tif (response.status >= 300 && response.status < 400) {\n\t\t\t\tredirectCount++;\n\t\t\t\tif (redirectCount > MAX_REDIRECTS) {\n\t\t\t\t\tthrow error(502, \"Too many redirects\");\n\t\t\t\t}\n\n\t\t\t\tconst location = response.headers.get(\"location\");\n\t\t\t\tif (!location) {\n\t\t\t\t\tthrow error(502, \"Redirect without Location header\");\n\t\t\t\t}\n\n\t\t\t\t// Resolve relative redirects against the current URL\n\t\t\t\tconst redirectUrl = new URL(location, currentUrl).toString();\n\n\t\t\t\tif (!isValidUrl(redirectUrl)) {\n\t\t\t\t\tlogger.warn(\n\t\t\t\t\t\t{ redirectUrl, originalUrl: targetUrl },\n\t\t\t\t\t\t\"Redirect to unsafe URL blocked (SSRF)\"\n\t\t\t\t\t);\n\t\t\t\t\tthrow error(403, \"Redirect target is not allowed\");\n\t\t\t\t}\n\n\t\t\t\tcurrentUrl = redirectUrl;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tbreak;\n\t\t}\n\t} finally {\n\t\tclearTimeout(timeoutId);\n\t}\n\n\tif (!response.ok) {\n\t\tlogger.error({ targetUrl, response }, \"Error fetching URL. Response not ok.\");","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/routes/api/fetch-url/+server.ts#L79-L115","documentation":"Log warning in the fetch-url GET handler: a redirect hop during manual redirect-following pointed to a URL rejected by isValidUrl (SSRF guard — non-HTTPS or private target), so the redirect chain is blocked and the fetch aborted.","triggerScenarios":"Thrown at ruflo/src/ruvocal/src/routes/api/fetch-url/+server.ts:97 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Do not follow redirects to private or non-HTTPS targets; request the final safe URL directly."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}