Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .jules/sentinel.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion apps/web/src/app/api/agents/dispatch/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/agents/status/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
);
}
Expand Down
3 changes: 1 addition & 2 deletions apps/web/src/app/api/extract-events/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [] },
});
}
Expand Down
3 changes: 2 additions & 1 deletion apps/web/src/app/api/jobs/[jobId]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/training/status/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
);
}
Expand Down
3 changes: 1 addition & 2 deletions apps/web/src/app/api/training/trigger/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand All @@ -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 },
);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/api/video/search/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
);
}
Expand Down
Loading