From 13e77f1c047f2372a82178068c6896d276257da5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 29 May 2026 04:59:19 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM]=20?= =?UTF-8?q?Sanitize=20third-party=20error=20responses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sanitized the API error responses in the file upload route. Previously, it exposed internal configuration state (Cloudinary setup) and detailed 3rd-party exceptions (`cloudinaryError`) to the client on HTTP 500. This change ensures we fail securely by emitting generic error messages to the client, while keeping detailed context strictly server-side. Co-authored-by: GerryK97 <210032986+GerryK97@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ src/app/api/upload/route.ts | 18 +++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 .jules/sentinel.md diff --git a/.jules/sentinel.md b/.jules/sentinel.md new file mode 100644 index 00000000..54c088f4 --- /dev/null +++ b/.jules/sentinel.md @@ -0,0 +1,4 @@ +## 2024-05-18 - Sanitize Third-Party Error Responses +**Vulnerability:** The API upload endpoint was exposing detailed internal configuration state (e.g. missing Cloudinary credentials) and raw third-party error objects (`cloudinaryError`) directly to clients in HTTP 500 responses. +**Learning:** Developers often pass full error objects from third-party services (like Cloudinary, AWS, etc) down to the client for debugging, inadvertently leaking internal architecture details and potentially sensitive configurations. +**Prevention:** Always fail securely by catching exceptions, logging the detailed error object strictly server-side, and returning a generic, safe error message to the API consumer. diff --git a/src/app/api/upload/route.ts b/src/app/api/upload/route.ts index 1664e115..84197dd2 100644 --- a/src/app/api/upload/route.ts +++ b/src/app/api/upload/route.ts @@ -6,13 +6,15 @@ export async function POST(request: NextRequest) { try { // Verify Cloudinary configuration if (!process.env.CLOUDINARY_CLOUD_NAME || !process.env.CLOUDINARY_API_KEY || !process.env.CLOUDINARY_API_SECRET) { + // 🛡️ SECURITY: Log the detailed missing config server-side but do not expose + // internal service requirements (like Cloudinary) to the client. console.error('Missing Cloudinary credentials:', { cloud_name: !!process.env.CLOUDINARY_CLOUD_NAME, api_key: !!process.env.CLOUDINARY_API_KEY, api_secret: !!process.env.CLOUDINARY_API_SECRET }); return NextResponse.json( - { error: 'Cloudinary is not configured. Please set environment variables.' }, + { error: 'Image upload service configuration error.' }, { status: 500 } ); } @@ -60,18 +62,16 @@ export async function POST(request: NextRequest) { } catch (error: any) { console.error('Upload error:', error); - // Return detailed error message - const errorMessage = error?.message || error?.error?.message || 'Failed to upload image'; - const errorDetails = { - error: errorMessage, + // 🛡️ SECURITY: Log detailed errors (like 3rd party API objects) server-side + // and fail securely by providing only a generic error to the client. + console.error('Full error details:', { + message: error?.message || error?.error?.message || 'Failed to upload image', details: error?.http_code ? `HTTP ${error.http_code}` : undefined, cloudinaryError: error?.error || undefined - }; - - console.error('Full error details:', errorDetails); + }); return NextResponse.json( - errorDetails, + { error: 'An error occurred during image upload.' }, { status: 500 } ); }