fix(eventstream): reject events with invalid UTF-8 topic (PILOT-277)#7
fix(eventstream): reject events with invalid UTF-8 topic (PILOT-277)#7matthew-pilot wants to merge 1 commit into
Conversation
ReadEvent now validates topic bytes with utf8.Valid() before casting to string. Without this check, an attacker can craft a topic with invalid UTF-8 that survives transport unchanged but gets silently mangled by json.Marshal (replacing invalid sequences with U+FFFD). This can be exploited to escape audit redaction (PILOT-284) — the wire-observed bytes differ from the JSON-logged value, yet both map to the same Go map key. Closes PILOT-277 (eventstream half)
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
🦾 Matthew PR Status — #7Title: fix(eventstream): reject events with invalid UTF-8 topic (PILOT-277) TicketsLabelsNone Files Changed
Next Actions
🦾 Auto-generated status check by matthew-pr-worker |
🦾 Matthew PR Explain — #7What this PR doesfix(eventstream): reject events with invalid UTF-8 topic (PILOT-277) Scope
TicketsFiles
Review Notes
🦾 Auto-generated explain by matthew-pr-worker |
🦾 Matthew PR Status — #7Title: fix(eventstream): reject events with invalid UTF-8 topic (PILOT-277) TicketsLabelsNone Files Changed
Next Actions
🦾 Auto-generated status check by matthew-pr-worker |
🦾 Matthew PR Explain — #7What this PR doesfix(eventstream): reject events with invalid UTF-8 topic (PILOT-277) Scope
TicketsFiles
Review Notes
🦾 Auto-generated explain by matthew-pr-worker |
What failed
ReadEventineventstream.go:61casts raw network bytes to string viastring(topic)without UTF-8 validation. An attacker can send a topic containing invalid UTF-8 bytes that survive transport unchanged but get silently mangled by downstreamjson.Marshal(which replaces invalid sequences with U+FFFD). This creates a discrepancy between wire-observed and JSON-logged topic values, exploitable as an audit-redaction escape (PILOT-284).Why this fix
Added
utf8.Valid(topic)check before thestring()cast. If validation fails,ReadEventreturns an error. This is the simpler, safer approach vs sanitization — invalid input should be rejected at the protocol boundary.Verification
go build ./...✓go vet ./...✓go test ./...✓ (all tests pass, including newTestEventTopicInvalidUTF8)Scope
eventstream.go: +5 lines (import + validation check)zz_event_wire_test.go: +16 lines (new test)Both files: 2 files, +21 LoC. Small tier.
Closes PILOT-277 (eventstream half)