Skip to content

Stop sending the stack trace to the browser - #716

Merged
blaipr merged 1 commit into
mainfrom
fix/no-stack-trace-in-response
Aug 13, 2026
Merged

Stop sending the stack trace to the browser#716
blaipr merged 1 commit into
mainfrom
fix/no-stack-trace-in-response

Conversation

@blaipr

@blaipr blaipr commented Aug 13, 2026

Copy link
Copy Markdown
Member

The bug

The web entry point's top-level catch built its error response like this:

ActionResponse::error($e->getMessage(), $e->getTrace())

The second argument is the response's data, and ActionResponse::jsonSerialize() puts it straight into the JSON body. So any JSON endpoint that threw answered the browser with the exception's full stack trace: every frame's file, class and function, and the arguments each frame was called with wherever the platform is configured to keep them.

In a password manager, those arguments are the worst possible thing to put in an error page.

The API entry point has only ever sent the message — this makes the web one match.

Nothing is lost

processException($e) runs a line earlier and has already written the trace to the log, which is where it belongs.

Testing

A test that drives a real JSON action into a failure and asserts the response carries the message, a 500, and no data. It fails without the change — the data comes back as the trace array — and it also checks the body for the application path, so a trace in any other shape would still be caught.

Found while covering the entry points (#715), which is also where its sibling was found: Init.php:335 calls ini_set('session.gc_maxlifetime', …) after the session has already been started, so it always fails silently and the configured timeout never reaches PHP's own garbage collector. That one is a separate change.

The web entry point's top-level catch built its error response as
ActionResponse::error($e->getMessage(), $e->getTrace()), and the second argument
is the response's data — which a JSON action serialises straight to the browser.
So any JSON endpoint that threw answered with every frame's file, class and
function, and the arguments each was called with wherever the platform is
configured to keep them.

In a password manager those arguments are the worst possible thing to put in an
error page. The API entry point has only ever sent the message; this makes the
web one match.

Nothing is lost: processException() has already written the trace to the log,
which is where it belongs.

The test fails without the change — the response's data comes back as the trace
array — and it checks the body for the application path as well, so a trace in
any other shape would still be caught.
@blaipr
blaipr merged commit 4756b69 into main Aug 13, 2026
8 checks passed
@blaipr
blaipr deleted the fix/no-stack-trace-in-response branch August 13, 2026 16:49
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.

1 participant