Repository navigation
fix(html_escape): name code points, not bytes, in numeric references - #342
Merged
Mzack9999 merged 1 commit intoOct 25, 2026
Merged
Conversation
This was referenced Sep 29, 2026
strToNumEntities read one byte at a time and wrote &#<byte>;, so a
multi-byte character turned into a run of references that decode back to
mojibake rather than the original text:
html_escape("こんにちは", true)
before: &projectdiscovery#227;&projectdiscovery#129;&projectdiscovery#147;&projectdiscovery#227;&projectdiscovery#130;&projectdiscovery#147;...
after: こんにちは
Feeding that back through html_unescape returned "ã‚“ã¡ã¯" before and
"こんにちは" after. A numeric character reference names a Unicode code
point, so the loop now decodes a rune and advances by its width.
ASCII is unchanged, which is what the existing assertion covers, and a byte
that is not valid UTF-8 keeps the value it had before since there is no code
point to name it with.
CalvinTjoaquinn
force-pushed
the
fix/html-escape-codepoints
branch
from
September 29, 2026 06:23
99d874f to
2a6ace7
Compare
dogancanbakir
approved these changes
Oct 21, 2026
Mzack9999
approved these changes
Oct 25, 2026
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.
Fixes #356
html_escape(s, true)writes one numeric character reference per UTF-8 byte. A numeric reference names a Unicode code point, so anything outside ASCII comes out as a reference sequence that decodes to mojibake instead of the original text.Measured
こis U+3053, soこis the reference that names it.ãnames U+00E3, which isã, and that is exactly what a browser renders.Why
rune(escaped[i])converts a single byte, soこ(E3 81 93) became three references. The fix decodes a rune withutf8.DecodeRuneInStringand advances by its width.A byte that is not valid UTF-8 keeps its old spelling, since there is no code point to name it with, so binary input behaves as it did before.
Nothing else changes
The existing assertion is ASCII only and is byte-identical before and after:
Characters the escaping pass already has a named entity for never reach this loop.
ébecomeséand is copied across untouched, which the new test pins so a later change does not quietly start renumbering them.Verification
Reverting
util.goand keeping the new test:Each case also asserts
html_unescapereturns the original string, which is the property that was broken.With the change:
go test -race ./...passes andgolangci-lint run ./...reports 0 issues.Separate from #340 and #341, which touch
url_encodeindsl.go. No overlap.