fix: decode ES2015+ \u{...} extended unicode escapes in jsDecode - #1657
fix: decode ES2015+ \u{...} extended unicode escapes in jsDecode#1657fzipi wants to merge 2 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughChangesExtended Unicode escape decoding
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related issues
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1657 +/- ##
==========================================
+ Coverage 87.77% 87.80% +0.03%
==========================================
Files 178 178
Lines 9144 9170 +26
==========================================
+ Hits 8026 8052 +26
Misses 854 854
Partials 264 264
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@internal/transformations/js_decode_test.go`:
- Around line 29-62: Add test cases to the JavaScript decode table near the
existing extended Unicode escapes for leading-zero inputs \u{0ff01} and
\u{00ff01} expecting "!", a valid six-digit escape, and a malformed seven-digit
escape. Ensure the cases verify the helper’s 1–6 hexadecimal digit boundary and
reject the seven-digit form with the expected malformed-escape output.
In `@internal/transformations/js_decode.go`:
- Around line 53-56: The full-width ASCII folding in the decode logic only
handles exactly four hex digits, so update the folding in
jsExtendedUnicodeEscapeLen to numerically recognize U+FF01–U+FF5E across all
accepted 1–6 digit escape lengths, including leading-zero forms, and fold them
correctly. Add or extend boundary tests in js_decode_test.go covering the
1-digit through 6-digit valid lengths, especially leading-zero encodings and the
six-digit boundary.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 042e6ac3-9441-4898-a33f-d9248c865752
⛔ Files ignored due to path filters (1)
go.sumis excluded by!**/*.sum
📒 Files selected for processing (2)
internal/transformations/js_decode.gointernal/transformations/js_decode_test.go
9f11239 to
6928309
Compare
doJsDecode only recognized \uHHHH (exactly 4 hex digits). The \u{H...H}
extended code point escape (1-6 hex digits in braces), supported by
every modern JS engine since ES2015, fell through to the generic
escape branch: the backslash was dropped and the literal "u" kept,
leaving the rest ("{H...H}") uncorrected in the output -- so a keyword
spelled with \u{...} escapes (e.g. \u{61}\u{6c}\u{65}\u{72}\u{74} for
"alert") never got decoded at all.
See #1653
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The full-width-ASCII fold only applied when the escape had exactly 4
hex digits, so a leading-zero encoding of the same value -- \u{0ff01}
or \u{00ff01}, both numerically U+FF01 -- skipped the fold entirely
and decoded to the raw low byte instead of '!'. Trivially defeats the
fold's purpose (normalizing fullwidth-character evasion).
Now computes the fully resolved code point (same approach as
cssDecode's fix in #1658) and checks the fold range against that
value directly, independent of digit count or leading zeros.
Found by CodeRabbit review on this PR.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6928309 to
0e77092
Compare
|
|
||
| switch { | ||
|
|
||
| case (i+2 < inputLen) && (input[i+1] == 'u') && (input[i+2] == '{') && jsExtendedUnicodeEscapeLen(input, i+3) > 0: |
There was a problem hiding this comment.
just for my understanding, you are calling the jsExtendedUnicodeEscapeLen on the match case and below, so you will end up calling it twice anyway. Would it make sense to instead just branch the below inside an if and remove it from the case arm, like:
if j := jsExtendedUnicodeEscapeLen(input, i+3); j > 0 { ... do its thing ... }
| { | ||
| // 7 hex digits exceeds the 6-digit maximum: malformed, falls | ||
| // through to the generic escape handling unchanged. | ||
| input: "\\u{1234567}", |
There was a problem hiding this comment.
maybe some more tests:
\u{} // Some null cases \u{0} // Some null cases \u{41}\u0042 // Or something that tests the combination of both on a single line \u{0FF5e} // should produce ~ as well
Summary
doJsDecodeonly recognized\uHHHH(exactly 4 hex digits). The\u{H...H}extended code point escape (1-6 hex digits in braces), supported by every modern JS engine since ES2015, fell through to the generic escape branch — the backslash was dropped and the literalukept, leaving{H...H}uncorrected in the output.\u{H...H}, handled the same way as the existing\uHHHHcase: lower byte of the resolved value, with the same full-width-ASCII fold.}) fall through to the existing generic-escape handling unchanged.Fixes #1653.
Test plan
\u{61}\u{6c}\u{65}\u{72}\u{74}→alert(the reported bypass), single/double hex digit cases, full-width-ASCII fold (\u{ff01}→!), and malformed-escape fallback casesgo test ./...,go vet ./...,golangci-lint runall passBenchmark (
BenchmarkJSDecode, Apple M2,benchtime=1s)hello world\u{61}\u{6c}\u{65}\u{72}\u{74}(new)No allocation-count change on any pre-existing case; the new switch-case adds a few cheap byte comparisons per backslash encountered, within run-to-run noise on this machine.
Summary by CodeRabbit
\u{...}(1–6 hex digits).