[ENG-4058] Screen response bodies in the character encoding a client reads - #305
Merged
Merged
Conversation
|
Comprehensive charset-aware screening with robust JSON escape handling. 🎯 Quality: 100% Elite · 📦 Size: Large — consider splitting if possible 🛡️ Standards: Not checked — 451 lines changed, over your team's 400-line limit, and nothing checked before it was opened. Coding agents can call the 🤖 Authorship: Agent-written — Claude Code, going by its own attribution. Whether a person read it is unknown; coding agents can call the 📈 This month: Your 164th PR — above team average · Averaging Excellent |
patchstackdave
force-pushed
the
fix/response-charset
branch
from
September 28, 2026 14:44
3ff71c6 to
e18e94c
Compare
patchstackdave
changed the base branch from
main
to
fix/header-redaction-without-body
September 28, 2026 14:44
patchstackdave
force-pushed
the
fix/response-charset
branch
5 times, most recently
from
September 28, 2026 17:38
9800bbe to
73a8529
Compare
patchstackdave
added this pull request to stack #317
September 29, 2026 08:03
Contributor
Author
|
/review |
mariojgt
approved these changes
Sep 29, 2026
patchstackdave
force-pushed
the
fix/response-charset
branch
from
September 29, 2026 09:27
73a8529 to
45cff96
Compare
A body whose bytes do not read as UTF-8 (UTF-16, or a legacy charset with bytes outside ASCII) is recorded as an unsupported-charset skip and sent unchanged. A legacy charset over plain ASCII is still screened, and a rewrite that would add non-ASCII to it is withheld. JSON bodies are screened with their \uXXXX and \/ escapes read as a JSON parser reads them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A body that starts with a UTF-8 byte-order mark is screened without it and rewritten with it, on both paths, so the client still reads the rewrite as UTF-8. A body in an unsupported charset on the Node path still gets the rules decided on headers alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
patchstackdave
force-pushed
the
fix/response-charset
branch
from
September 29, 2026 09:30
45cff96 to
bad800a
Compare
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.
Stacked on #297. Review that first; this PR's own changes are the last two commits.
Response screening reads text as UTF-8. This makes the reading match what the client will see, and reports a body that can't be read that way.
Character encodings
charsetdoes.unsupported-charsetskip, with the charset, throughonSkipandcoverage(). That covers UTF-16/32 (declared, or marked by a byte-order mark) and any other charset whose bytes include non-ASCII, NUL, or ESC. Rules decided on headers alone ([ENG-4058] Apply header-only rules when the body is not screened #297) still apply to it on both paths.maskWith) gets the existing withheld response rather than being sent under the wrong charset.JSON escapes
\uXXXX(printable ASCII) and\/escapes read as a JSON parser reads them, so a value is matched as the client will see it.<,>,&,', and\/after<) stay escaped in a rewritten body, and it parses to the same values. Non-ASCII escapes are left as they are.Decoding other charsets so they can be screened is not part of this change.
Tests:
tests/protect/response-character-encoding.test.tscovers, on the fetch path and the Node path (headers set before the body and throughwriteHead()):Two tests in
tests/protect/response-json-structure.test.tsnow rewrite a non-ASCII escape (\u00e9) instead of a printable ASCII one. Screening reads a printable ASCII escape as its character, so a rewrite can no longer land inside one; a non-ASCII escape stays escaped, and still exercises the structure check.Validation: full suite (3,971 passed, 7 skipped), typecheck, and build.
Part of ENG-4058.
🤖 Generated with Claude Code