Skip to content

fix(security): stop leaking Python tracebacks to HTTP clients#283

Merged
ChuckBuilds merged 3 commits intoChuckBuilds:mainfrom
5ymb01:fix/traceback-client-leak
Mar 20, 2026
Merged

fix(security): stop leaking Python tracebacks to HTTP clients#283
ChuckBuilds merged 3 commits intoChuckBuilds:mainfrom
5ymb01:fix/traceback-client-leak

Conversation

@5ymb01
Copy link
Copy Markdown
Contributor

@5ymb01 5ymb01 commented Mar 12, 2026

Summary

  • Remove 13 instances where traceback.format_exc() was sent in API JSON responses to HTTP clients
  • 5 error_response(details=traceback.format_exc()) → generic "Internal server error - check server logs"
  • 6 jsonify({'traceback': traceback.format_exc()}) → removed traceback key from response
  • 2 jsonify({'details': error_details}) → replaced with logger.error() server-side logging
  • Debug-mode traceback display in app.py error handlers is preserved (guarded by app.debug)

Rationale

Leaking Python tracebacks to HTTP clients exposes internal file paths, library versions, and code structure. This information can aid attackers in crafting targeted exploits. Server-side logging via logger.error() preserves debugging capability without client exposure.

Test plan

  • grep -n "details=traceback\|'traceback': traceback\|'details': error_details" web_interface/blueprints/api_v3.py — zero matches
  • Trigger a 500 error via API → response contains message but no traceback or details with stack frames
  • Check server logs still contain full traceback for debugging

Co-Authored-By: 5ymb01 noreply@github.com
Co-Authored-By: Claude Opus 4.6 noreply@anthropic.com

Summary by CodeRabbit

  • Bug Fixes

    • API error responses now return a consistent, generic message for unexpected failures, preventing exposure of internal error details.
    • Error handling across endpoints has been standardized so clients receive uniform 500 responses for server errors.
  • Chores

    • Server-side logging enhanced to record errors without leaking internal traces to responses.

Replace 13 instances where traceback.format_exc() was sent in API
JSON responses (via `details=`, `traceback:`, or `details:` keys).

- 5 error_response(details=traceback.format_exc()) → generic message
- 6 jsonify({'traceback': traceback.format_exc()}) → removed key
- 2 jsonify({'details': error_details}) → logger.error() instead

Tracebacks in debug mode (app.py error handlers) are preserved as
they are guarded by app.debug and expected during development.

Co-Authored-By: 5ymb01 <noreply@github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 12, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 73707efd-665f-4458-8579-65e2599341ba

📥 Commits

Reviewing files that changed from the base of the PR and between a06187a and d485973.

📒 Files selected for processing (1)
  • web_interface/blueprints/api_v3.py
✅ Files skipped from review due to trivial changes (1)
  • web_interface/blueprints/api_v3.py

📝 Walkthrough

Walkthrough

Replaced per-endpoint traceback exposure with generic "Internal server error" responses and converted print/traceback diagnostics to logger-based logging across API v3 endpoints, preserving HTTP status codes while removing stack traces from error payloads.

Changes

Cohort / File(s) Summary
API v3 error handling & logging
web_interface/blueprints/api_v3.py
Removed traceback details from responses; replaced print/traceback usage with logger.exception / logger.warning / logger.error; standardized failure responses (primarily 500) to a generic "Internal server error - check server logs" across many routes (config/save, schedule endpoints, plugin endpoints, system actions, and other API routes).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly describes the main security fix: preventing Python tracebacks from being exposed to HTTP clients, which matches the primary objective of the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@5ymb01
Copy link
Copy Markdown
Contributor Author

5ymb01 commented Mar 13, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

1 similar comment
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web_interface/blueprints/api_v3.py`:
- Around line 413-417: The response is leaking raw exception text to clients via
the error_response call (e.g., the call using ErrorCode.CONFIG_SAVE_FAILED and
f"Error saving schedule configuration: {str(e)}"); instead, remove str(e) from
the client-facing message and return a generic message (e.g., "Error saving
schedule configuration") or a user-safe error id, while logging the full
exception server-side with traceback; update all similar sites that use
str(e)/exception text in error_response (the occurrences you noted) to use the
generic client message and ensure the exception is passed to the server logger
rather than the response.
- Around line 6066-6068: The except block that currently returns a sanitized 500
(the except Exception as e handling that returns
jsonify({'status':'error','message':str(e)}), 500) must log the full exception
before returning: use the existing structured logger (e.g., processLogger or app
logger) and call its exception()/error() with the traceback and a context tag
like "[NHL Recent]" so remote debugging is possible; capture the traceback or
use logger.exception("... [NHL Recent]") to include stack trace, then continue
returning the sanitized JSON 500 response.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5db7edf-b332-47fd-ac09-dbd55eb0ff7c

📥 Commits

Reviewing files that changed from the base of the PR and between 76c5bf5 and 3853b53.

📒 Files selected for processing (1)
  • web_interface/blueprints/api_v3.py

… logging

Address CodeRabbit review findings:
- Replace str(e) in error_response message fields with generic messages
- Replace import logging/traceback + manual format with logger.exception()
- Add logger.exception() to 6 jsonify handlers that were swallowing errors
- All exception details now logged server-side only, not sent to clients

Co-Authored-By: 5ymb01 <noreply@github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
web_interface/blueprints/api_v3.py (2)

1015-1037: Avoid duplicate traceback logging in save_raw_main_config error path.

This block now uses logger.exception(...), but it still manually builds/logs traceback text earlier in the same except, causing duplicate stack traces and mixed logging style.

♻️ Proposed cleanup
-    except Exception as e:
-        import logging
-        import traceback
-        from src.exceptions import ConfigError
-
-        # Log the full error for debugging
-        error_msg = f"Error saving raw main config: {str(e)}\n{traceback.format_exc()}"
-        logging.error(error_msg)
-
-        # Extract more specific error message if it's a ConfigError
-        logger.exception("[RawConfig] Failed to save raw main config")
+    except Exception as e:
+        from src.exceptions import ConfigError
+        logger.exception("[RawConfig] Failed to save raw main config")

As per coding guidelines "Use structured logging with context (e.g., [NHL Recent]) for logging messages".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web_interface/blueprints/api_v3.py` around lines 1015 - 1037, In
save_raw_main_config remove the manual logging.error/traceback.format_exc()
block to avoid duplicate stack traces and rely on the existing logger.exception
call for structured logging; replace the logger.exception call's message with a
contextual tag (e.g., "[RawConfig] Failed to save raw main config") if it isn't
already, ensure you only use logger.exception (not logging.error) in the except
block, and keep the existing ConfigError check and error_response logic
unchanged.

6054-6055: Use endpoint-specific log context instead of a shared [API] Unexpected error tag.

Using the same tag across multiple handlers makes production triage harder. Consider distinct tags per endpoint (e.g., [PluginAssetsUpload], [OfTheDayUpload], etc.).

🧭 Example pattern
-        logger.exception("[API] Unexpected error")
+        logger.exception("[PluginAssetsUpload] Unexpected error")

As per coding guidelines "Use structured logging with context (e.g., [NHL Recent]) for logging messages" and "Implement comprehensive logging for remote debugging on Raspberry Pi".

Also applies to: 6204-6205, 6251-6252, 6297-6298, 6469-6470, 6497-6498

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web_interface/blueprints/api_v3.py` around lines 6054 - 6055, Replace the
generic logger.exception("[API] Unexpected error") message in each route handler
with an endpoint-specific structured context: e.g.,
logger.exception("[PluginAssetsUpload] Unexpected error processing %s %s",
request.method, request.path) or logger.exception("[OfTheDayUpload] ...", ...)
so logs include the unique tag (PluginAssetsUpload, OfTheDayUpload, etc.),
request.method/path or handler name, and the exception (logger.exception
preserves traceback). Apply this change for the shown occurrence and the other
similar spots (the other logger.exception calls referenced) so each endpoint
uses a distinct tag and includes request context for easier triage.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web_interface/blueprints/api_v3.py`:
- Around line 1015-1037: In save_raw_main_config remove the manual
logging.error/traceback.format_exc() block to avoid duplicate stack traces and
rely on the existing logger.exception call for structured logging; replace the
logger.exception call's message with a contextual tag (e.g., "[RawConfig] Failed
to save raw main config") if it isn't already, ensure you only use
logger.exception (not logging.error) in the except block, and keep the existing
ConfigError check and error_response logic unchanged.
- Around line 6054-6055: Replace the generic logger.exception("[API] Unexpected
error") message in each route handler with an endpoint-specific structured
context: e.g., logger.exception("[PluginAssetsUpload] Unexpected error
processing %s %s", request.method, request.path) or
logger.exception("[OfTheDayUpload] ...", ...) so logs include the unique tag
(PluginAssetsUpload, OfTheDayUpload, etc.), request.method/path or handler name,
and the exception (logger.exception preserves traceback). Apply this change for
the shown occurrence and the other similar spots (the other logger.exception
calls referenced) so each endpoint uses a distinct tag and includes request
context for easier triage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 34c0d4b0-2626-4d72-a762-5baf08dc1ff9

📥 Commits

Reviewing files that changed from the base of the PR and between 3853b53 and a06187a.

📒 Files selected for processing (1)
  • web_interface/blueprints/api_v3.py

Address CodeRabbit nitpicks:
- Remove manual import logging/traceback + logging.error() that duplicated
  the logger.exception() call in save_raw_main_config
- Apply same fix to save_raw_secrets_config: replace str(e) in client
  response with generic message, use logger.exception() for server-side

Co-Authored-By: 5ymb01 <noreply@github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@ChuckBuilds ChuckBuilds merged commit f718305 into ChuckBuilds:main Mar 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants