[3.0] Strip arguments and objects from logged backtraces - #9315
Open
albertlast wants to merge 1 commit into
Open
[3.0] Strip arguments and objects from logged backtraces#9315albertlast wants to merge 1 commit into
albertlast wants to merge 1 commit into
Conversation
ErrorHandlerService::log() json encodes the backtrace before storing it.
The backtraces it collects itself pass DEBUG_BACKTRACE_IGNORE_ARGS, but
that only applies when no backtrace was supplied:
$backtrace = $backtrace ?? debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
catch() supplies one, from Throwable::getTrace(), and that keeps both the
call arguments and the bound objects. Two consequences:
Anything a member submitted can end up in the error log, including the
password posted to the login form, since it is simply an argument a few
frames down.
Encoding an object reads its properties, which can throw. When it does,
the new error arrives while the first one is still being logged, and an
error that would only have been logged becomes an uncaught fatal that
hides the original. That is what turned a background task failure into a
white page for logged in members:
Uncaught Error: Cannot access uninitialized non-nullable property
SMF\User::$username by reference
#1 Sources/Utils.php(1539): json_encode(Array, 0, 512)
#2 ErrorHandlerService.php(286): SMF\Utils::jsonEncode(Array)
#3 ErrorHandlerService.php(185): ...->log('Cannot access u...')
Drops both keys from every frame before encoding. File, line, function
and class are kept, which is what the log is for.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
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.
Note
This change was produced by an LLM. The code, the commit message and this
description were all written by Claude (Anthropic), driven by @albertlast. It has
not yet had human code review.
Everything stated below was verified by actually running it against a fresh
PostgreSQL install of this branch, rather than only reasoned about. Even so,
please review it as untrusted work: the diagnosis may be right while the fix is
not what SMF would prefer stylistically or architecturally.
Description
ErrorHandlerService::log()json encodes the backtrace before storing it. Thebacktraces it collects itself pass
DEBUG_BACKTRACE_IGNORE_ARGS, but that onlyapplies when no backtrace was supplied:
catch()always supplies one, fromThrowable::getTrace(), and that keeps both thecall arguments and the bound objects. Two consequences:
1. Sensitive data reaches the error log. Anything a member submitted can end up
in
smf_log_errors, including the password posted to the login form — it is simplyan argument a few frames down.
2. A caught error can escalate into an uncaught fatal. Encoding an object reads
its properties, which can throw. When it does, the new error arrives while the first
one is still being logged, and an error that would only have been logged becomes a
fatal that hides the original. Observed on a logged in page load:
Note the same line number appearing twice: the handler re-triggered the very error it
was logging. The underlying defect there is fixed separately in #9314, but the
amplification is worth fixing on its own — it turns any such error into a white page
and destroys the diagnostic.
This drops both keys from every frame before encoding. File, line, function and class
are kept, which is what the log is for.
Possibly worth a separate look
While here, this looked wrong but is not changed by this PR:
DEBUG_BACKTRACE_IGNORE_ARGSis2andDEBUG_BACKTRACE_PROVIDE_OBJECTis1, sothe bitwise
&evaluates to0rather than combining the flags, and the comment doesnot describe what the expression does. Left alone deliberately to keep this diff
focused, and because the sanitisation above makes it moot for safety.
How this was verified
After this change, the error that previously produced an uncaught fatal was logged as
an ordinary
generalerror and the page still returned HTTP 200. The stored backtraceis clean and usable — it is what located #9314:
[{"file":"...Sources/User.php","line":1476,"function":"saveBatch","class":"SMF\User","type":"::"}, {"file":"...Sources/User.php","line":4701,"function":"save","class":"SMF\User","type":"->"}, {"file":"...Sources/User.php","line":2931,"function":"setLastVisit","class":"SMF\User","type":"->"}, {"file":"...Sources/Forum.php","line":565,"function":"loadMe","class":"SMF\User","type":"::"}]Issues References (Fixes|Related|Closes)