Skip to content

fix: prevent lexer byte-offset drift on invalid UTF-8 input - #4

Merged
Mzack9999 merged 2 commits into
projectdiscovery:masterfrom
zainnadeem786:fix-invalid-utf8-slice-panic
Jun 15, 2026
Merged

fix: prevent lexer byte-offset drift on invalid UTF-8 input#4
Mzack9999 merged 2 commits into
projectdiscovery:masterfrom
zainnadeem786:fix-invalid-utf8-slice-panic

Conversation

@zainnadeem786

Copy link
Copy Markdown

Summary

Fix a slice-bounds panic caused by invalid UTF-8 input drifting the lexer's byte cursor away from the original expression.

This issue was originally identified while investigating a Nuclei crash reported in projectdiscovery/nuclei#7462.

Root Cause

lexerStream maintains two positions while parsing expressions:

  • position (rune index)
  • strPosition (byte offset into the original source string)

When invalid UTF-8 bytes are encountered, Go's string iteration decodes them as utf8.RuneError while consuming a single byte from the source string.

However, the lexer advanced strPosition using:

utf8.RuneLen(character)

For utf8.RuneError, utf8.RuneLen returns 3, causing the byte cursor to drift ahead of the actual source position.

A later token could then enter the reuse-string fast path in readUntilFalse() and attempt to slice beyond the end of sourceString, resulting in:

panic: runtime error: slice bounds out of range

Fix

Use the actual decoded byte width when handling utf8.RuneError during both forward and backward cursor movement.

For valid UTF-8 input, the existing fast path and behavior remain unchanged.

Tests

Added regression coverage for:

  • Multiple invalid UTF-8 bytes (reproduces nuclei#7462)
  • Single invalid UTF-8 byte
  • Valid multibyte UTF-8 characters
  • Encoded U+FFFD characters
  • Truncated UTF-8 sequences

Verified that expressions continue to tokenize correctly and no panic occurs.

Validation

go test -run '^TestUTF8Parsing$' -count=1
go test -count=1
go vet ./...

All tests pass.

Risk Assessment

Low risk.

The change is isolated to lexer cursor accounting for invalid UTF-8 input.

  • Valid UTF-8 behavior is unchanged.
  • Tokenization behavior remains unchanged.
  • Existing allocations and parsing paths remain unchanged.
  • Malformed input continues to decode as replacement runes but no longer corrupts byte-offset tracking.

References

@Mzack9999
Mzack9999 merged commit 5ee2581 into projectdiscovery:master Jun 15, 2026
@zainnadeem786
zainnadeem786 deleted the fix-invalid-utf8-slice-panic branch June 15, 2026 10:31
dwisiswant0 pushed a commit to projectdiscovery/nuclei that referenced this pull request Jun 17, 2026
…8 input (#7464)

Upgrade github.com/projectdiscovery/govaluate from
v0.0.0-20260504230327-80320480bb6e to
v0.0.0-20260615100919-5ee2581bbf7e to consume the fix merged in
projectdiscovery/govaluate#4.

The govaluate lexer advanced strPosition by utf8.RuneLen(utf8.RuneError)
== 3 for invalid bytes, even though only 1 byte was consumed. This
caused byte-offset drift past the actual string length and a
`slice bounds out of range` panic in readUntilFalse.

Nuclei's expressions.Evaluate only caught govaluate errors, not panics,
so targets returning invalid UTF-8 in response data could crash the
entire process.

Fixes #7462
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.

Add bounds check to lexerStream.rewind negative-amount branch

2 participants