diff --git a/frontend/src/app/api/[..._path]/route.ts b/frontend/src/app/api/[..._path]/route.ts index 2ccf6ed..c4aae3a 100644 --- a/frontend/src/app/api/[..._path]/route.ts +++ b/frontend/src/app/api/[..._path]/route.ts @@ -6,6 +6,7 @@ import { resolveApiUrl } from "@/lib/connections/resolve"; import { getAuthMode, usesNextAuth } from "@/types/auth-mode"; import { generateUserJWT } from "@/lib/auth/jwt"; import { isPrivateUrl } from "@/lib/utils/url-validation"; +import { internalErrorResponse } from "@/lib/api/error-response"; function getCorsHeaders(req: NextRequest) { const origin = req.headers.get("origin"); @@ -156,8 +157,7 @@ async function handleRequest(req: NextRequest, method: string) { }, }); } catch (e) { - const error = e as Error; - return NextResponse.json({ error: error.message }, { status: 500 }); + return internalErrorResponse(e, "proxy request failed"); } } diff --git a/frontend/src/app/api/admin/upload/route.ts b/frontend/src/app/api/admin/upload/route.ts index b257dee..7c9aedf 100644 --- a/frontend/src/app/api/admin/upload/route.ts +++ b/frontend/src/app/api/admin/upload/route.ts @@ -3,6 +3,7 @@ import { auth } from "@/lib/auth"; import { isAdmin } from "@/types/auth-mode"; import type { UserRole } from "@/types/auth-mode"; import { writeFile, mkdir, access, constants } from "fs/promises"; +import { internalErrorResponse } from "@/lib/api/error-response"; import path from "path"; const ALLOWED_TYPES = [ @@ -96,13 +97,7 @@ export async function POST(request: NextRequest) { return NextResponse.json({ url, filename }); } catch (error) { - console.error("Upload error:", error); - return NextResponse.json( - { - error: `Failed to upload file: ${error instanceof Error ? error.message : "Unknown error"}`, - }, - { status: 500 }, - ); + return internalErrorResponse(error, "admin file upload failed"); } } diff --git a/frontend/src/app/api/langsmith/runs/route.ts b/frontend/src/app/api/langsmith/runs/route.ts index 148b95a..2c5908d 100644 --- a/frontend/src/app/api/langsmith/runs/route.ts +++ b/frontend/src/app/api/langsmith/runs/route.ts @@ -2,6 +2,7 @@ import { Client, type Run } from "langsmith"; import { NextRequest, NextResponse } from "next/server"; import { LangSmithRun, buildRunHierarchy } from "@/types/langsmith"; import { usesNextAuth } from "@/types/auth-mode"; +import { internalErrorResponse } from "@/lib/api/error-response"; // LangSmith Run 객체를 LangSmithRun 형식으로 변환 function convertRun(run: Run): LangSmithRun { @@ -137,10 +138,6 @@ export async function GET(req: NextRequest) { return NextResponse.json({ runs, hierarchy }); } catch (error) { - console.error("Failed to fetch LangSmith runs:", error); - return NextResponse.json( - { error: error instanceof Error ? error.message : "Unknown error" }, - { status: 500 }, - ); + return internalErrorResponse(error, "LangSmith runs fetch failed"); } } diff --git a/frontend/src/app/api/upload/route.ts b/frontend/src/app/api/upload/route.ts index 6ce07c3..fbff943 100644 --- a/frontend/src/app/api/upload/route.ts +++ b/frontend/src/app/api/upload/route.ts @@ -2,6 +2,7 @@ import { NextRequest, NextResponse } from "next/server"; import { auth } from "@/lib/auth"; import { usesNextAuth } from "@/types/auth-mode"; import { getSetting } from "@/lib/services/settings.service"; +import { internalErrorResponse } from "@/lib/api/error-response"; import { writeFile, mkdir, access, constants } from "fs/promises"; import path from "path"; @@ -106,13 +107,7 @@ export async function POST(request: NextRequest) { return NextResponse.json({ url, filename }); } catch (error) { - console.error("Upload error:", error); - return NextResponse.json( - { - error: `Failed to upload file: ${error instanceof Error ? error.message : "Unknown error"}`, - }, - { status: 500 }, - ); + return internalErrorResponse(error, "user file upload failed"); } } diff --git a/frontend/src/lib/api/error-response.ts b/frontend/src/lib/api/error-response.ts new file mode 100644 index 0000000..cbd8abe --- /dev/null +++ b/frontend/src/lib/api/error-response.ts @@ -0,0 +1,14 @@ +import { NextResponse } from "next/server"; + +/** + * Return a generic 500 JSON response while logging the real error server-side. + * Prevents leaking internal hostnames, ports, file-system paths, or API keys + * to clients (OWASP A05:2021 — Security Misconfiguration). + */ +export function internalErrorResponse(error: unknown, context: string) { + console.error(`[api] ${context}`, error); + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 }, + ); +}