From 0d4241392f021bbaf5d6c056be616f19cab353cc Mon Sep 17 00:00:00 2001 From: Aryan Shrestha Date: Wed, 8 Jul 2026 10:09:04 +0545 Subject: [PATCH] Potential fix for code scanning alert no. 5: Server-side request forgery Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> --- app/api/instagram/image/route.ts | 34 +++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/app/api/instagram/image/route.ts b/app/api/instagram/image/route.ts index 3c05082..37ed88c 100644 --- a/app/api/instagram/image/route.ts +++ b/app/api/instagram/image/route.ts @@ -11,6 +11,38 @@ const isAllowedHost = (hostname: string) => { ); }; +const isAllowedImageUrl = (url: URL) => { + return url.protocol === "https:" && isAllowedHost(url.hostname); +}; + +const fetchWithValidatedRedirects = async ( + initialUrl: URL, + maxRedirects = 5 +): Promise => { + let currentUrl = initialUrl; + + for (let i = 0; i <= maxRedirects; i++) { + if (!isAllowedImageUrl(currentUrl)) { + throw new Error("Invalid redirect host"); + } + + const response = await fetch(currentUrl.toString(), { redirect: "manual" }); + + if (response.status >= 300 && response.status < 400) { + const location = response.headers.get("location"); + if (!location) { + throw new Error("Redirect missing location"); + } + currentUrl = new URL(location, currentUrl); + continue; + } + + return response; + } + + throw new Error("Too many redirects"); +}; + export async function GET(request: Request) { const { searchParams } = new URL(request.url); const src = searchParams.get("src"); @@ -31,7 +63,7 @@ export async function GET(request: Request) { } try { - const response = await fetch(url.toString(), { redirect: "follow" }); + const response = await fetchWithValidatedRedirects(url); if (!response.ok) { return NextResponse.json({ error: "Failed to fetch image" }, { status: 502 }); }