Skip to content

fix: stop sending python tracebacks to remote dbus callers#659

Merged
bdraco merged 2 commits into
mainfrom
fix/no-traceback-leak
May 16, 2026
Merged

fix: stop sending python tracebacks to remote dbus callers#659
bdraco merged 2 commits into
mainfrom
fix/no-traceback-leak

Conversation

@bdraco
Copy link
Copy Markdown
Member

@bdraco bdraco commented May 15, 2026

What

Sanitize the two error-response bodies that were embedding traceback.format_exc() / traceback.format_tb() verbatim in messages sent back to remote callers. The wire body now contains only the exception class name; the full traceback is logged locally via _LOGGER.exception for operator diagnostics.

Why

A method handler that raised an unexpected exception sent back a body like:

An internal error occurred: ValueError('bad signature').
Traceback (most recent call last):
  File "/home/nick/.local/lib/python3.13/site-packages/dbus_fast/message_bus.py", line 818, in _process_message
    ...

That discloses absolute filesystem paths (revealing the install location and user-account names like /home/<user>/.../site-packages/...), exact source line numbers, function names, locals referenced in frames, and library versions to any peer that can invoke a method on the service. On the system bus this means any unprivileged process. The information is useful for an attacker chaining further exploits (path-traversal targeting, version fingerprinting, internal class structure for crafted payloads) and unnecessary for legitimate callers, who only need to know the call failed.

Two sites were leaking:

  1. src/dbus_fast/message_bus.py:837INTERNAL_ERROR reply for a raising add_message_handler callback. This is the path Security: Full Python tracebacks sent to remote callers leak file paths and code structure #645 calls out.
  2. src/dbus_fast/send_reply.py:45SERVICE_ERROR reply for a raising exported service-interface method. Sibling leak the issue did not flag; same class of bug, same fix.

How

Both bodies become "<prefix>: <ExceptionClass>". The full traceback is logged via _LOGGER.exception on the bus side so operators retain diagnostics. send_reply.py gains its own module logger since it had none.

import traceback removed from message_bus.py (no longer needed); send_reply.py drops traceback in favour of logging.

Tests

  • tests/service/test_methods.py::test_methods — extended the existing throws_unexpected_error assertion to pin the sanitized SERVICE_ERROR body (no Traceback, no File ", no str(e) content; class name Exception present).
  • tests/test_aio_low_level.py::test_internal_error_reply_does_not_leak_traceback — new test for the INTERNAL_ERROR path: registers an add_message_handler callback that raises ValueError("must not appear on the wire"), sends a call, asserts the reply body is sanitized (no traceback, no path, no exception message; class name ValueError present).

closes #645

Two error paths embedded traceback.format_exc() / format_tb() in the
error message body sent back to the caller:

- message_bus.py:837 — INTERNAL_ERROR for a raising add_message_handler
  callback (the path issue #645 calls out).
- send_reply.py:45 — SERVICE_ERROR for a raising exported service
  method (the sibling leak; same class of bug).

The traceback discloses absolute install paths (revealing the install
location and user-account names like /home/<user>/.../site-packages/...),
exact source line numbers, function names, locals referenced in
frames, and library versions to any peer that can invoke a method on
the service. Useful for an attacker chaining further exploits;
unnecessary for legitimate callers who just need to know the call
failed.

Sanitize both wire bodies to "<prefix>: <ExceptionClass>" and log
the full traceback locally via _LOGGER.exception so operators retain
diagnostics. send_reply.py gains its own logger since it had none.

closes #645
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented May 15, 2026

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing fix/no-traceback-leak (460124c) with main (62ae5d0)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (a6fd177) during the generation of this report, so 62ae5d0 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

…ation

#636 added test_send_reply_generic_exception with `assert "boom" in
body` as an incidental coverage assertion for the SERVICE_ERROR
branch. After the traceback-leak fix the wire body no longer carries
the exception's str(), only the class name, so the old assertion
fails. Update it to match — pin that "boom" is NOT in the body and
"RuntimeError" IS, mirroring the live-bus test added alongside the
production change.
@codecov
Copy link
Copy Markdown

codecov Bot commented May 15, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.55%. Comparing base (62ae5d0) to head (460124c).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #659      +/-   ##
==========================================
+ Coverage   89.31%   89.55%   +0.23%     
==========================================
  Files          29       29              
  Lines        3511     3512       +1     
  Branches      602      602              
==========================================
+ Hits         3136     3145       +9     
+ Misses        226      218       -8     
  Partials      149      149              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR mitigates an information-disclosure issue in dbus-fast by ensuring error replies sent over D-Bus no longer embed Python tracebacks, while still preserving operator diagnostics via local logging.

Changes:

  • Sanitize INTERNAL_ERROR replies produced when add_message_handler callbacks raise, returning only the exception class name.
  • Sanitize SERVICE_ERROR replies produced when exported service-interface methods raise, returning only the exception class name and logging the full traceback locally.
  • Extend/add tests to assert that reply bodies do not contain tracebacks, file paths, or exception messages.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/dbus_fast/message_bus.py Removes traceback leakage from INTERNAL_ERROR replies for raising user message handlers.
src/dbus_fast/send_reply.py Logs full tracebacks locally and sanitizes SERVICE_ERROR reply bodies to exception class name only.
tests/test_send_reply.py Updates assertions to ensure SERVICE_ERROR reply bodies are sanitized.
tests/service/test_methods.py Strengthens service-method tests to verify sanitized error bodies for unexpected exceptions.
tests/test_aio_low_level.py Adds a low-level regression test covering the INTERNAL_ERROR path for raising message handlers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@bdraco bdraco merged commit f6af2eb into main May 16, 2026
29 checks passed
@bdraco bdraco deleted the fix/no-traceback-leak branch May 16, 2026 00:02
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.

Security: Full Python tracebacks sent to remote callers leak file paths and code structure

2 participants