Skip to content

Use consistent HTML escaping in error details fragment - #3466

Open
iliaal wants to merge 2 commits into
slimphp:4.xfrom
iliaal:fix/html-error-renderer-escape-consistency
Open

Use consistent HTML escaping in error details fragment#3466
iliaal wants to merge 2 commits into
slimphp:4.xfrom
iliaal:fix/html-error-renderer-escape-consistency

Conversation

@iliaal

@iliaal iliaal commented Aug 23, 2026

Copy link
Copy Markdown

HtmlErrorRenderer::renderExceptionFragment() escapes the exception message and stack trace with bare htmlentities(), while the title and description are escaped with explicit htmlspecialchars(..., ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'). The two escape sites therefore behave differently across the supported PHP range: htmlentities() default flags gained ENT_QUOTES only in PHP 8.1, so on 7.4/8.0 single quotes in the message pass through unescaped, and the charset is inherited from the default_charset ini rather than pinned to UTF-8.

This aligns the fragment escaping with the same explicit call used everywhere else in the renderer, making behavior identical on every supported PHP version.

The exception message and trace in renderExceptionFragment() used bare
htmlentities(), whose default flags differ across PHP versions and
inherit the default_charset ini, while the title and description are
escaped with explicit ENT_QUOTES | ENT_SUBSTITUTE flags and a pinned
UTF-8 charset. Align the fragment escaping with the same explicit call
so behavior is identical on every supported PHP version.
@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 99.457% (+0.002%) from 99.455% — iliaal:fix/html-error-renderer-escape-consistency into slimphp:4.x

htmlspecialchars($exception->getMessage(), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8')
);

$html .= sprintf('<div><strong>File:</strong> %s</div>', $exception->getFile());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

File is still emitted without HTML escaping

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Agreed. getFile() is string and a path can contain <>&"'. I'll escape it with the same htmlspecialchars(..., ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') call as message and trace.


$html .= sprintf('<div><strong>File:</strong> %s</div>', $exception->getFile());

$html .= sprintf('<div><strong>Line:</strong> %s</div>', $exception->getLine());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is still emitted without HTML escaping

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

getLine() is int, so escaping is a no-op. I'll still add it for uniformity.

The real sibling is Type: anonymous class names embed the file path. I'll escape Type (and Code, which has no return type on Throwable) in the same pass.

File, Type, Code, and Line were interpolated into the details fragment
without escaping. File paths and anonymous class names can contain HTML
metacharacters, and Throwable::getCode() is untyped. Route every fragment
field through the same htmlspecialchars() flags as title and description.
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.

3 participants