From 5709282200e2c54abfc1fc8e0157316a2c9f9fcd Mon Sep 17 00:00:00 2001 From: maziggy Date: Sat, 4 Apr 2026 12:54:31 +0200 Subject: [PATCH] Add authentication to bug report debug logging endpoints The bug report endpoints (start-logging, stop-logging, submit) had no authentication, allowing anyone on the network to enable debug logging, retrieve sanitized system logs, and trigger bug report submissions when auth was enabled. All three now require permission when auth is enabled: start-logging requires settings:update, stop-logging and submit require settings:read. Endpoints remain open when auth is disabled (default). --- CHANGELOG.md | 1 + backend/app/api/routes/bug_report.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a44cd4c9..235064f36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to Bambuddy will be documented in this file. ### Security - **Path Traversal in File Upload Endpoints** — Archive upload endpoints (`/upload`, `/upload-bulk`, `/{id}/source`, `/source-by-name`, `/{id}/f3d`, `/{id}/timelapse`) used the client-supplied filename directly in file paths without stripping directory components. An authenticated attacker could write files outside the intended directory via directory traversal (e.g. `../../evil.3mf`). All upload endpoints now sanitize filenames by extracting only the basename before constructing paths. Reported responsibly by Sacha Vaudey via security@bambuddy.cool. +- **Unauthenticated Bug Report Endpoints** — The bug report endpoints (`/start-logging`, `/stop-logging`, `/submit`) had no authentication, allowing anyone on the network to enable debug logging, retrieve system logs, and trigger bug report submissions with system diagnostics when authentication was enabled. All three endpoints now require authentication — `start-logging` requires `settings:update` permission, `stop-logging` and `submit` require `settings:read`. Endpoints remain open when authentication is disabled (the default). Reported responsibly by Sacha Vaudey via security@bambuddy.cool. ### Fixed - **Thumbnails Broken After Backend Restart** — Archive and library thumbnails returned 401 Unauthorized after a backend restart because stream tokens are stored in memory and lost on restart. The frontend now detects failed token-protected image loads and automatically refreshes the stream token, so thumbnails recover without a page reload. diff --git a/backend/app/api/routes/bug_report.py b/backend/app/api/routes/bug_report.py index 6328a8651..03fc10d83 100644 --- a/backend/app/api/routes/bug_report.py +++ b/backend/app/api/routes/bug_report.py @@ -12,7 +12,10 @@ from backend.app.api.routes.support import ( _get_recent_sanitized_logs, _set_debug_setting, ) +from backend.app.core.auth import RequirePermissionIfAuthEnabled from backend.app.core.database import async_session +from backend.app.core.permissions import Permission +from backend.app.models.user import User from backend.app.services.bug_report import submit_report from backend.app.services.printer_manager import printer_manager @@ -45,7 +48,9 @@ class StopLoggingResponse(BaseModel): @router.post("/start-logging", response_model=StartLoggingResponse) -async def start_logging(): +async def start_logging( + _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_UPDATE), +): """Enable debug logging and push all printers for fresh data.""" async with async_session() as db: was_debug, _ = await _get_debug_setting(db) @@ -66,7 +71,10 @@ async def start_logging(): @router.post("/stop-logging", response_model=StopLoggingResponse) -async def stop_logging(was_debug: bool = Query(default=False)): +async def stop_logging( + was_debug: bool = Query(default=False), + _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_READ), +): """Collect logs and restore previous log level.""" logs = await _get_recent_sanitized_logs() @@ -80,8 +88,11 @@ async def stop_logging(was_debug: bool = Query(default=False)): @router.post("/submit", response_model=BugReportResponse) -async def submit_bug_report(report: BugReportRequest): - """Submit a bug report. No auth required — anyone should be able to report bugs.""" +async def submit_bug_report( + report: BugReportRequest, + _: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_READ), +): + """Submit a bug report. Requires auth when authentication is enabled.""" support_info = None if report.include_support_info: try: