/claim #5838

Proposed Changes

  • XSS context analyzer (pkg/fuzz/analyzers/xss/): Uses html.Tokenizer for browser-grade reflection context detection (body, attribute, script, comment, event handler, URL, encoded).
  • Event handler detection: 60+ event attributes (e.g. onclick, onerror, onload) with case-insensitive matching; optimized to 0 allocations on the hot path (byte-level prefix check).
  • Character survival (CharacterSet): Tracks server-side encoded/allowed characters (angle brackets, quotes, backticks, parenthesis, equals, etc.); payloads filtered so only viable ones are tried.
  • Context-aware payload selection and replay verification: Reduces blind fuzzing and false positives.
    • Enhanced Verification: Added checks for onload handlers, tag injections (<svg, <img, <script), and alert(document.domain) in event handler contexts.
  • Malformed/truncated HTML: Drain logic using substring windows ensures reflections are found even when the tokenizer stops (unclosed tags, truncated output), with improved precision.
  • Entity-Encoded Marker Support: Correctly handles markers that are entity-encoded in the raw HTML but decoded in token data (fallback to token data inspection).
  • Encoding detection: Scoped double-encoding and unicode-escape detection (checks window around reflection); analyzer fails fast when the response suggests heavy encoding.
  • Runtime wiring: Analyzer response fields (ResponseBody, ResponseHeaders, ResponseStatusCode) wired into runtime options.
  • Fuzzplayground: Six XSS endpoints (/xss/body, /xss/attribute, /xss/script, /xss/comment, /xss/event, /xss/encoded) for integration testing.
  • Integration: Six templates and handlers (body, attribute, script, encoded, comment, event); templates and syntax/template docs updated.
  • Benchmarks: Nine benchmarks for context detection, event-handler check, and payload selection.

Proof

1) Unit tests

go test -vet=off -v -count=1 ./pkg/fuzz/analyzers/xss
# github.com/shoenig/go-m1cpu
../../../go/pkg/mod/github.com/shoenig/go-m1cpu@v0.1.6/cpu.go:75:17: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant]
../../../go/pkg/mod/github.com/shoenig/go-m1cpu@v0.1.6/cpu.go:77:16: warning: variable length array folded to constant array as an extension [-Wgnu-folding-constant]
=== RUN TestAnalyzerName
--- PASS: TestAnalyzerName (0.00s)
=== RUN TestApplyInitialTransformation_DefaultCanary
--- PASS: TestApplyInitialTransformation_DefaultCanary (0.00s)
=== RUN TestApplyInitialTransformation_CustomCanary
--- PASS: TestApplyInitialTransformation_CustomCanary (0.00s)
=== RUN TestApplyInitialTransformation_NoPlaceholder
--- PASS: TestApplyInitialTransformation_NoPlaceholder (0.00s)
=== RUN TestAnalyze_HTMLBodyReflection
--- PASS: TestAnalyze_HTMLBodyReflection (0.00s)
=== RUN TestAnalyze_AttributeReflection
--- PASS: TestAnalyze_AttributeReflection (0.00s)
=== RUN TestAnalyze_ScriptReflection
--- PASS: TestAnalyze_ScriptReflection (0.00s)
=== RUN TestAnalyze_EncodedReflectionNegative
--- PASS: TestAnalyze_EncodedReflectionNegative (0.00s)
=== RUN TestAnalyze_NoReflection
--- PASS: TestAnalyze_NoReflection (0.00s)
=== RUN TestAnalyze_CommentReflection_NoPanic
--- PASS: TestAnalyze_CommentReflection_NoPanic (0.00s)
=== RUN TestAnalyze_EventHandlerReflection
--- PASS: TestAnalyze_EventHandlerReflection (0.00s)
=== RUN TestAnalyze_DoubleEncodingNegative
--- PASS: TestAnalyze_DoubleEncodingNegative (0.00s)
=== RUN TestVerifyReplayBody_EventHandlerContext
--- PASS: TestVerifyReplayBody_EventHandlerContext (0.00s)
=== RUN TestAnalyze_NilOptions
--- PASS: TestAnalyze_NilOptions (0.00s)
=== RUN TestAnalyze_EmptyResponseBody
--- PASS: TestAnalyze_EmptyResponseBody (0.00s)
=== RUN TestAnalyze_EmptyMarker
--- PASS: TestAnalyze_EmptyMarker (0.00s)
=== RUN TestVerifyReplayBody_ScriptContext
--- PASS: TestVerifyReplayBody_ScriptContext (0.00s)
=== RUN TestVerifyReplayBody_HTMLContext
--- PASS: TestVerifyReplayBody_HTMLContext (0.00s)
=== RUN TestVerifyReplayBody_AttributeContext
--- PASS: TestVerifyReplayBody_AttributeContext (0.00s)
=== RUN TestVerifyReplayBody_CommentContext
--- PASS: TestVerifyReplayBody_CommentContext (0.00s)
=== RUN TestVerifyReplayBody_URLContext
--- PASS: TestVerifyReplayBody_URLContext (0.00s)
=== RUN TestDetectReflections_EmptyInputs
--- PASS: TestDetectReflections_EmptyInputs (0.00s)
=== RUN TestDetectReflections_HTMLText
--- PASS: TestDetectReflections_HTMLText (0.00s)
=== RUN TestDetectReflections_HTMLTextParagraph
--- PASS: TestDetectReflections_HTMLTextParagraph (0.00s)
=== RUN TestDetectReflections_HTMLTextNested
--- PASS: TestDetectReflections_HTMLTextNested (0.00s)
=== RUN TestDetectReflections_AttributeDoubleQuoted
--- PASS: TestDetectReflections_AttributeDoubleQuoted (0.00s)
=== RUN TestDetectReflections_AttributeSingleQuoted
--- PASS: TestDetectReflections_AttributeSingleQuoted (0.00s)
=== RUN TestDetectReflections_AttributeUnquoted
--- PASS: TestDetectReflections_AttributeUnquoted (0.00s)
=== RUN TestDetectReflections_AttributeHref
--- PASS: TestDetectReflections_AttributeHref (0.00s)
=== RUN TestDetectReflections_AttributeSrc
--- PASS: TestDetectReflections_AttributeSrc (0.00s)
=== RUN TestDetectReflections_AttributeMixedQuotingSameTag
--- PASS: TestDetectReflections_AttributeMixedQuotingSameTag (0.00s)
=== RUN TestDetectReflections_SelfClosingTag
--- PASS: TestDetectReflections_SelfClosingTag (0.00s)
=== RUN TestDetectReflections_EventHandlerOnclick
--- PASS: TestDetectReflections_EventHandlerOnclick (0.00s)
=== RUN TestDetectReflections_EventHandlerOnError
--- PASS: TestDetectReflections_EventHandlerOnError (0.00s)
=== RUN TestDetectReflections_EventHandlerOnMouseOver
--- PASS: TestDetectReflections_EventHandlerOnMouseOver (0.00s)
=== RUN TestDetectReflections_EventHandlerOnFocus
--- PASS: TestDetectReflections_EventHandlerOnFocus (0.00s)
=== RUN TestDetectReflections_EventHandlerMixedCase
--- PASS: TestDetectReflections_EventHandlerMixedCase (0.00s)
=== RUN TestDetectReflections_NonEventOnAttribute
--- PASS: TestDetectReflections_NonEventOnAttribute (0.00s)
=== RUN TestDetectReflections_ScriptBlock
--- PASS: TestDetectReflections_ScriptBlock (0.00s)
=== RUN TestDetectReflections_ScriptStringDouble
--- PASS: TestDetectReflections_ScriptStringDouble (0.00s)
=== RUN TestDetectReflections_ScriptStringSingle
--- PASS: TestDetectReflections_ScriptStringSingle (0.00s)
=== RUN TestDetectReflections_ScriptTemplate
--- PASS: TestDetectReflections_ScriptTemplate (0.00s)
=== RUN TestDetectReflections_ScriptInsideSVG
--- PASS: TestDetectReflections_ScriptInsideSVG (0.00s)
=== RUN TestDetectReflections_MultipleScriptsMarkerInSecond
--- PASS: TestDetectReflections_MultipleScriptsMarkerInSecond (0.00s)
=== RUN TestDetectReflections_Comment
--- PASS: TestDetectReflections_Comment (0.00s)
=== RUN TestDetectReflections_MultiLineComment
--- PASS: TestDetectReflections_MultiLineComment (0.00s)
=== RUN TestDetectReflections_Textarea
--- PASS: TestDetectReflections_Textarea (0.00s)
=== RUN TestDetectReflections_Title
--- PASS: TestDetectReflections_Title (0.00s)
=== RUN TestDetectReflections_Style
--- PASS: TestDetectReflections_Style (0.00s)
=== RUN TestDetectReflections_MultipleReflections
--- PASS: TestDetectReflections_MultipleReflections (0.00s)
=== RUN TestDetectReflections_PriorityOrder
--- PASS: TestDetectReflections_PriorityOrder (0.00s)
=== RUN TestDetectReflections_ScriptWinsOverAll
--- PASS: TestDetectReflections_ScriptWinsOverAll (0.00s)
=== RUN TestDetectReflections_CaseInsensitiveTags
--- PASS: TestDetectReflections_CaseInsensitiveTags (0.00s)
=== RUN TestDetectReflections_MalformedUnclosedTag
--- PASS: TestDetectReflections_MalformedUnclosedTag (0.00s)
=== RUN TestDetectReflections_TruncatedDocument
--- PASS: TestDetectReflections_TruncatedDocument (0.00s)
=== RUN TestDetectReflections_DrainCountsCorrectly
--- PASS: TestDetectReflections_DrainCountsCorrectly (0.00s)
=== RUN TestDetectReflections_LargePage
--- PASS: TestDetectReflections_LargePage (0.00s)
=== RUN TestDetectAvailableChars_AllPresent
--- PASS: TestDetectAvailableChars_AllPresent (0.00s)
=== RUN TestDetectAvailableChars_AngleBracketsEncoded
--- PASS: TestDetectAvailableChars_AngleBracketsEncoded (0.00s)
=== RUN TestDetectAvailableChars_QuotesEncoded
--- PASS: TestDetectAvailableChars_QuotesEncoded (0.00s)
=== RUN TestDetectAvailableChars_NotInOriginal
--- PASS: TestDetectAvailableChars_NotInOriginal (0.00s)
=== RUN TestDetectAvailableChars_ParenthesisEncoded
--- PASS: TestDetectAvailableChars_ParenthesisEncoded (0.00s)
=== RUN TestDetectDoubleEncoding
--- PASS: TestDetectDoubleEncoding (0.00s)
=== RUN TestDetectUnicodeEscape
--- PASS: TestDetectUnicodeEscape (0.00s)
=== RUN TestContextTypeString
--- PASS: TestContextTypeString (0.00s)
=== RUN TestIsURLAttribute
--- PASS: TestIsURLAttribute (0.00s)
=== RUN TestIsEventHandler
=== RUN TestIsEventHandler/onclick
=== RUN TestIsEventHandler/ONCLICK
=== RUN TestIsEventHandler/OnClick
=== RUN TestIsEventHandler/onmouseover
=== RUN TestIsEventHandler/onerror
=== RUN TestIsEventHandler/onload
=== RUN TestIsEventHandler/onfocus
=== RUN TestIsEventHandler/onanimationiteration
=== RUN TestIsEventHandler/onfocusin
=== RUN TestIsEventHandler/onpointerdown
=== RUN TestIsEventHandler/ontoggle
=== RUN TestIsEventHandler/onwheel
=== RUN TestIsEventHandler/class
=== RUN TestIsEventHandler/href
=== RUN TestIsEventHandler/src
=== RUN TestIsEventHandler/data-onclick
=== RUN TestIsEventHandler/onnonexistent
=== RUN TestIsEventHandler/on
=== RUN TestIsEventHandler/o
--- PASS: TestIsEventHandler (0.00s)
--- PASS: TestIsEventHandler/onclick (0.00s)
--- PASS: TestIsEventHandler/ONCLICK (0.00s)
--- PASS: TestIsEventHandler/OnClick (0.00s)
--- PASS: TestIsEventHandler/onmouseover (0.00s)
--- PASS: TestIsEventHandler/onerror (0.00s)
--- PASS: TestIsEventHandler/onload (0.00s)
--- PASS: TestIsEventHandler/onfocus (0.00s)
--- PASS: TestIsEventHandler/onanimationiteration (0.00s)
--- PASS: TestIsEventHandler/onfocusin (0.00s)
--- PASS: TestIsEventHandler/onpointerdown (0.00s)
--- PASS: TestIsEventHandler/ontoggle (0.00s)
--- PASS: TestIsEventHandler/onwheel (0.00s)
--- PASS: TestIsEventHandler/class (0.00s)
--- PASS: TestIsEventHandler/href (0.00s)
--- PASS: TestIsEventHandler/src (0.00s)
--- PASS: TestIsEventHandler/data-onclick (0.00s)
--- PASS: TestIsEventHandler/onnonexistent (0.00s)
--- PASS: TestIsEventHandler/on (0.00s)
--- PASS: TestIsEventHandler/o (0.00s)
=== RUN TestDetectReflections_ContextStyle_Explicit
--- PASS: TestDetectReflections_ContextStyle_Explicit (0.00s)
=== RUN TestDetectReflections_ContextRCDATA_TextArea
--- PASS: TestDetectReflections_ContextRCDATA_TextArea (0.00s)
=== RUN TestDetectReflections_ContextAttributeUnquoted_Explicit
--- PASS: TestDetectReflections_ContextAttributeUnquoted_Explicit (0.00s)
=== RUN TestSelectPayloads_HTMLTextAllChars
--- PASS: TestSelectPayloads_HTMLTextAllChars (0.00s)
=== RUN TestSelectPayloads_HTMLTextAngleBracketsFiltered
--- PASS: TestSelectPayloads_HTMLTextAngleBracketsFiltered (0.00s)
=== RUN TestSelectPayloads_AttributeDoubleQuoted
--- PASS: TestSelectPayloads_AttributeDoubleQuoted (0.00s)
=== RUN TestSelectPayloads_AttributeQuotesFiltered
--- PASS: TestSelectPayloads_AttributeQuotesFiltered (0.00s)
=== RUN TestSelectPayloads_ScriptString
--- PASS: TestSelectPayloads_ScriptString (0.00s)
=== RUN TestSelectPayloads_URLAttribute
--- PASS: TestSelectPayloads_URLAttribute (0.00s)
=== RUN TestSelectPayloads_Comment
--- PASS: TestSelectPayloads_Comment (0.00s)
=== RUN TestSelectPayloads_EventHandler
--- PASS: TestSelectPayloads_EventHandler (0.00s)
=== RUN TestSelectPayloads_EventHandlerNoParens
--- PASS: TestSelectPayloads_EventHandlerNoParens (0.00s)
=== RUN TestSelectPayloads_MaxAttempts
--- PASS: TestSelectPayloads_MaxAttempts (0.00s)
=== RUN TestSelectPayloads_MaxAttemptsFloat
--- PASS: TestSelectPayloads_MaxAttemptsFloat (0.00s)
=== RUN TestSelectPayloads_UnknownContext
--- PASS: TestSelectPayloads_UnknownContext (0.00s)
=== RUN TestCanUsePayload_AngleBracketRequired
--- PASS: TestCanUsePayload_AngleBracketRequired (0.00s)
=== RUN TestCanUsePayload_BacktickRequired
--- PASS: TestCanUsePayload_BacktickRequired (0.00s)
=== RUN TestCanUsePayload_ParenthesisRequired
--- PASS: TestCanUsePayload_ParenthesisRequired (0.00s)
PASS
ok github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers/xss 1.241s

2) Benchmarks

go test -vet=off -run='^$' -bench=. -benchmem ./pkg/fuzz/analyzers/xss
goos: darwin
goarch: arm64
pkg: github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers/xss
cpu: Apple M2
BenchmarkDetectContext_NoReflection-8 208402182 5.873 ns/op 0 B/op 0 allocs/op
BenchmarkDetectContext_HTMLContext-8 974512 1258 ns/op 4920 B/op 8 allocs/op
BenchmarkDetectContext_ScriptContext-8 1123948 1023 ns/op 4824 B/op 8 allocs/op
BenchmarkDetectContext_AttributeContext-8 689889 1560 ns/op 5332 B/op 17 allocs/op
BenchmarkDetectContext_EventHandler-8 755950 1438 ns/op 5173 B/op 15 allocs/op
BenchmarkDetectContext_LargePage-8 10000 116039 ns/op 86928 B/op 1217 allocs/op
BenchmarkDetectContext_MultipleReflections-8 489505 2280 ns/op 5480 B/op 20 allocs/op
BenchmarkIsEventHandler-8 17701758 66.97 ns/op 0 B/op 0 allocs/op
BenchmarkSelectPayloads-8 5075552 232.6 ns/op 128 B/op 1 allocs/op
PASS
ok github.com/projectdiscovery/nuclei/v3/pkg/fuzz/analyzers/xss 13.782s

3) Compile / integration check

go test -vet=off ./cmd/integration-test ./pkg/protocols/http -run TestDoesNotExist -count=1
? github.com/projectdiscovery/nuclei/v3/cmd/integration-test [no test files]
ok github.com/projectdiscovery/nuclei/v3/pkg/protocols/http 3.100s [no tests to run]

Checklist

  • PR created against the correct branch (dev)
  • All checks passed (unit tests, benchmarks, compile)
  • Tests and benchmarks added
  • Documentation updated (syntax and template docs)

Claim

Total prize pool $200
Total paid $0
Status Pending
Submitted February 12, 2026
Last updated February 12, 2026

Contributors

AS

Ashutosh Sharma

@ashuwhy

100%

Sponsors

PR

ProjectDiscovery

@projectdiscovery

$200