fix(simulation): stop returning Python tracebacks in API error responses - #745
Open
andesyteoss wants to merge 1 commit into
Open
fix(simulation): stop returning Python tracebacks in API error responses#745andesyteoss wants to merge 1 commit into
andesyteoss wants to merge 1 commit into
Conversation
Return only the exception message to clients; log full traceback server-side via logger.error(..., exc_info=True). Prevents disclosure of internal paths, library versions, and code structure (CWE-209).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
fix(simulation): stop returning Python tracebacks in API error responses
Summary
The Flask blueprint
backend/app/api/simulation.pycurrently returnstraceback.format_exc()inside the JSON body of every 500 response (around 20 endpoints). Any client that triggers a handledExceptiongets back the full Python stack trace, which discloses:MiroFish's own code.This is a textbook CWE-209: Generation of Error Message Containing Sensitive Information. On its own the impact is information disclosure (Low/Info), but it's a useful recon primitive for an attacker planning a follow-up (dependency-CVE targeting, path guessing for other file endpoints, etc.).
Why this is reachable by an unauthenticated attacker
grep -n "before_request\|@login_required" backend/app/api/simulation.pyreturns nothing).origins: "*", so any origin can call the API from a browser.graph_id,simulation_id,entity_uuid) that are easy to make invalid, which is enough to trip theexcept Exceptionbranch and produce the leaky response.Fix
Replace the leaking pattern
with
The full traceback is still captured server-side via
logger.error(..., exc_info=True)so operators keep the debugging signal; only the client-facing JSON is stripped. Theimport tracebackline is also removed since it's no longer used.Scope:
backend/app/api/simulation.pyonly, ~20 handlers. Diff is +62/-93 in a single file — no behavior change beyond the response body shape.Proof of concept
With the backend running locally (
python backend/run.pyor however you normally start it):Before the fix, the JSON response contains a
"traceback"field with the full Python stack, absolute paths, and library internals. After the fix, the response is{"success": false, "error": "..."}with no stack trace, and the traceback is written to the server log instead.Every route mentioned above exists in
backend/app/api/simulation.py(e.g. line 77@simulation_bp.route('/entities/<graph_id>', ...)).Testing
traceback, whileexc_info=Trueproduces the full trace in the server log.Adversarial review
Before submitting we tried to disprove this. Things we considered:
DEBUG=Falseenough? No —DEBUGonly controls Flask's own default 500 page and the interactive debugger. These handlers explicitly build the JSON body themselves and includetraceback.format_exc()regardless of debug mode.before_request,login_required, JWT/session middleware, and router-level auth dependencies. None are applied to the simulation blueprint. Combined withCORS(origins="*"), the endpoints are reachable by any network-adjacent attacker.Note for maintainers (out of scope for this PR)
The same
"traceback": traceback.format_exc()pattern exists in a few other files (backend/app/api/graph.py,backend/app/api/report.py). We kept this PR narrowly scoped tosimulation.pyto keep the diff reviewable, but you may want to apply the same treatment there in a follow-up.