From 4c90d1d4c933e0bb71589a95b1f32e0628408fc6 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 18:18:24 +0000 Subject: [PATCH 1/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20Fix=20internal=20error=20message=20leakage=20in=20API=20rou?= =?UTF-8?q?tes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 Severity: MEDIUM 💡 Vulnerability: Exposes raw backend error messages directly to the client 🎯 Impact: Could leak internal architecture details or timeout diagnostics 🔧 Fix: Log the detailed error internally and return a generic safe message ✅ Verification: Verified via linting and tests --- .jules/sentinel.md | 4 ++++ apps/web/src/app/api/agents/dispatch/route.ts | 2 +- apps/web/src/app/api/agents/status/route.ts | 2 +- apps/web/src/app/api/extract-events/route.ts | 3 +-- apps/web/src/app/api/jobs/[jobId]/route.ts | 3 ++- apps/web/src/app/api/training/status/route.ts | 2 +- apps/web/src/app/api/training/trigger/route.ts | 3 +-- apps/web/src/app/api/video/search/route.ts | 2 +- 8 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index a58dd10fe..3985a7d43 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -6,3 +6,7 @@ **Vulnerability:** API routes were returning internal server exceptions and stack traces directly to the client via `HTTPException(..., detail=str(e))`. **Learning:** Developers often unintentionally leak sensitive deployment context (e.g., paths, database errors) when relying on generic exception catching blocks. **Prevention:** Hardcode static error strings for unexpected 500 exceptions (e.g., `detail="Internal server error"`) while ensuring the full exception trace is securely logged server-side. Every sanitized 500 handler in `router.py`, `main.py`, and mounted routers (e.g. `reporting_routes.py`) now logs via `logger.error(..., exc_info=True)` so the traceback is preserved for internal monitoring without ever reaching the client. Guard against regressions with tests that assert the response body equals the generic message AND excludes the raised exception string (status-code-only assertions are insufficient). +## 2025-01-21 - Prevent internal error leakage in API routes +**Vulnerability:** The API routes for proxying requests exposed the raw `error.message` from failed `fetch` calls directly to the client. +**Learning:** Returning `error.message` from a backend fetch can inadvertently leak internal architecture details, such as backend hostnames, IPs, or connection timeout diagnostics, which attackers could use for reconnaissance. +**Prevention:** Catch external request errors, log the detailed error internally (e.g., via `console.error`), and return a generic, non-revealing error message (e.g., "Failed to communicate with backend service") to the client. diff --git a/apps/web/src/app/api/agents/dispatch/route.ts b/apps/web/src/app/api/agents/dispatch/route.ts index 29c940733..a668a7195 100644 --- a/apps/web/src/app/api/agents/dispatch/route.ts +++ b/apps/web/src/app/api/agents/dispatch/route.ts @@ -83,7 +83,7 @@ export async function POST(request: Request) { } catch (error) { console.error('Agent dispatch error:', error); return NextResponse.json( - { error: 'Failed to dispatch agents', details: String(error) }, + { error: 'Failed to dispatch agents' }, { status: 502 }, ); } diff --git a/apps/web/src/app/api/agents/status/route.ts b/apps/web/src/app/api/agents/status/route.ts index c142bf352..c7cd33b30 100644 --- a/apps/web/src/app/api/agents/status/route.ts +++ b/apps/web/src/app/api/agents/status/route.ts @@ -36,7 +36,7 @@ export async function GET(request: Request) { } catch (error) { console.error('Agent status error:', error); return NextResponse.json( - { error: 'Failed to get agent status', details: String(error) }, + { error: 'Failed to get agent status' }, { status: 502 }, ); } diff --git a/apps/web/src/app/api/extract-events/route.ts b/apps/web/src/app/api/extract-events/route.ts index 8eb8f8b56..7adc8af92 100644 --- a/apps/web/src/app/api/extract-events/route.ts +++ b/apps/web/src/app/api/extract-events/route.ts @@ -255,11 +255,10 @@ Respond with ONLY valid JSON matching the required structure.`; return NextResponse.json({ success: true, provider, data: parsed }); } catch (error) { console.error('Event extraction error:', error); - const message = error instanceof Error ? error.message : String(error); return NextResponse.json({ success: false, - error: message, + error: 'Event extraction failed', data: { events: [], actions: [], summary: '', topics: [] }, }); } diff --git a/apps/web/src/app/api/jobs/[jobId]/route.ts b/apps/web/src/app/api/jobs/[jobId]/route.ts index c9da65176..f6c3ceb83 100644 --- a/apps/web/src/app/api/jobs/[jobId]/route.ts +++ b/apps/web/src/app/api/jobs/[jobId]/route.ts @@ -38,8 +38,9 @@ export async function GET( headers: { 'Content-Type': 'application/json' }, }); } catch (error) { + console.error('Job proxy error:', error); return NextResponse.json( - { error: error instanceof Error ? error.message : String(error) }, + { error: 'Failed to fetch job status' }, { status: 502 }, ); } diff --git a/apps/web/src/app/api/training/status/route.ts b/apps/web/src/app/api/training/status/route.ts index 282378b6c..9db4aa85a 100644 --- a/apps/web/src/app/api/training/status/route.ts +++ b/apps/web/src/app/api/training/status/route.ts @@ -39,7 +39,7 @@ export async function GET() { } catch (error) { console.error('Training status error:', error); return NextResponse.json( - { error: 'Failed to read training status', details: String(error) }, + { error: 'Failed to read training status' }, { status: 500 }, ); } diff --git a/apps/web/src/app/api/training/trigger/route.ts b/apps/web/src/app/api/training/trigger/route.ts index 656f73890..72a3c9ce1 100644 --- a/apps/web/src/app/api/training/trigger/route.ts +++ b/apps/web/src/app/api/training/trigger/route.ts @@ -232,7 +232,6 @@ export async function POST(request: Request) { } catch (uploadError) { return NextResponse.json({ error: 'Upload/trigger failed', - details: String(uploadError), fallback: { message: 'Run manually:', commands: [ @@ -249,7 +248,7 @@ export async function POST(request: Request) { } catch (error) { console.error('Training trigger error:', error); return NextResponse.json( - { error: 'Failed to process training request', details: String(error) }, + { error: 'Failed to process training request' }, { status: 500 }, ); } diff --git a/apps/web/src/app/api/video/search/route.ts b/apps/web/src/app/api/video/search/route.ts index 141b2c6c5..08b55d6eb 100644 --- a/apps/web/src/app/api/video/search/route.ts +++ b/apps/web/src/app/api/video/search/route.ts @@ -53,7 +53,7 @@ export async function GET(request: Request) { } catch (error: any) { console.error('Video Search Error:', error); return NextResponse.json( - { error: error.message || 'Internal server error during vector search' }, + { error: 'Internal server error during vector search' }, { status: 500 } ); } From f856d4623f97c4171acda774fa2d5626e675aab8 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 1 Aug 2026 18:32:48 +0000 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM?= =?UTF-8?q?]=20Fix=20internal=20error=20message=20leakage=20in=20API=20rou?= =?UTF-8?q?tes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 Severity: MEDIUM 💡 Vulnerability: Exposes raw backend error messages directly to the client 🎯 Impact: Could leak internal architecture details or timeout diagnostics 🔧 Fix: Log the detailed error internally and return a generic safe message ✅ Verification: Verified via linting and tests