From 8dfd25613d3d51bb3357d19241db56140558fbd3 Mon Sep 17 00:00:00 2001 From: woikos Date: Tue, 6 Jan 2026 05:51:34 +0100 Subject: [PATCH] Fix corrupted events with zero-filled IDs/pubkeys/sigs (v0.47.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add validation in GetEventIdBySerial to ensure sei value is 32 bytes - Fix fallback-to-legacy bug: return error instead of attempting legacy unmarshal on compact format data when event ID lookup fails - Add upfront validation in UnmarshalCompactEvent for eventId length - Prevents events with all-zero IDs from being returned to clients Files modified: - pkg/database/serial_cache.go: Validate sei value is exactly 32 bytes - pkg/database/fetch-events-by-serials.go: Return error for compact format when eventId missing instead of falling back to legacy unmarshal - pkg/database/fetch-event-by-serial.go: Same fix for single event fetch - pkg/database/compact_event.go: Validate eventId is 32 bytes upfront - pkg/version/version: Bump to v0.47.1 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- pkg/database/compact_event.go | 5 +++++ pkg/database/fetch-event-by-serial.go | 15 +++++++++++---- pkg/database/fetch-events-by-serials.go | 20 ++++++++------------ pkg/database/serial_cache.go | 6 +++++- pkg/version/version | 2 +- 5 files changed, 30 insertions(+), 18 deletions(-) diff --git a/pkg/database/compact_event.go b/pkg/database/compact_event.go index a277450..f5949f0 100644 --- a/pkg/database/compact_event.go +++ b/pkg/database/compact_event.go @@ -240,6 +240,11 @@ func readUint40(r io.Reader) (value uint64, err error) { // The resolver is used to look up pubkeys and event IDs from serials. // The eventId parameter is the full 32-byte event ID (from SerialEventId table). func UnmarshalCompactEvent(data []byte, eventId []byte, resolver SerialResolver) (ev *event.E, err error) { + // Validate eventId upfront to prevent returning events with zero IDs + if len(eventId) != 32 { + return nil, errors.New("invalid eventId: must be exactly 32 bytes") + } + r := bytes.NewReader(data) ev = new(event.E) diff --git a/pkg/database/fetch-event-by-serial.go b/pkg/database/fetch-event-by-serial.go index 65661eb..92561a9 100644 --- a/pkg/database/fetch-event-by-serial.go +++ b/pkg/database/fetch-event-by-serial.go @@ -44,9 +44,12 @@ func (d *D) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error) { // Check if this is compact format if len(eventData) > 0 && eventData[0] == CompactFormatVersion { eventId, idErr := d.GetEventIdBySerial(ser) - if idErr == nil { - return UnmarshalCompactEvent(eventData, eventId, resolver) + if idErr != nil { + // Cannot decode compact format without event ID - return error + // DO NOT fall back to legacy unmarshal as compact format is not valid legacy format + return nil, fmt.Errorf("compact format inline but no event ID mapping for serial %d: %w", ser.Get(), idErr) } + return UnmarshalCompactEvent(eventData, eventId, resolver) } // Legacy binary format @@ -106,10 +109,14 @@ func (d *D) FetchEventBySerial(ser *types.Uint40) (ev *event.E, err error) { // Check if this is compact format if len(v) > 0 && v[0] == CompactFormatVersion { eventId, idErr := d.GetEventIdBySerial(ser) - if idErr == nil { - ev, err = UnmarshalCompactEvent(v, eventId, resolver) + if idErr != nil { + // Cannot decode compact format without event ID - return error + // DO NOT fall back to legacy unmarshal as compact format is not valid legacy format + err = fmt.Errorf("compact format evt but no event ID mapping for serial %d: %w", ser.Get(), idErr) return } + ev, err = UnmarshalCompactEvent(v, eventId, resolver) + return } // Check if we have valid data before attempting to unmarshal diff --git a/pkg/database/fetch-events-by-serials.go b/pkg/database/fetch-events-by-serials.go index 515d2eb..963f6df 100644 --- a/pkg/database/fetch-events-by-serials.go +++ b/pkg/database/fetch-events-by-serials.go @@ -149,12 +149,10 @@ func (d *D) fetchSmallEvent(txn *badger.Txn, ser *types.Uint40) (ev *event.E, er resolver := NewDatabaseSerialResolver(d, d.serialCache) eventId, idErr := d.GetEventIdBySerial(ser) if idErr != nil { - // Fall back to legacy unmarshal - ev = new(event.E) - if err = ev.UnmarshalBinary(bytes.NewBuffer(eventData)); err != nil { - return nil, err - } - return ev, nil + // Cannot decode compact format without event ID - return error + // DO NOT fall back to legacy unmarshal as compact format is not valid legacy format + log.W.F("fetchSmallEvent: compact format but no event ID mapping for serial %d: %v", ser.Get(), idErr) + return nil, idErr } return UnmarshalCompactEvent(eventData, eventId, resolver) } @@ -196,12 +194,10 @@ func (d *D) fetchLegacyEvent(txn *badger.Txn, ser *types.Uint40) (ev *event.E, e resolver := NewDatabaseSerialResolver(d, d.serialCache) eventId, idErr := d.GetEventIdBySerial(ser) if idErr != nil { - // Fall back to legacy unmarshal - ev = new(event.E) - if err = ev.UnmarshalBinary(bytes.NewBuffer(v)); err != nil { - return nil, err - } - return ev, nil + // Cannot decode compact format without event ID - return error + // DO NOT fall back to legacy unmarshal as compact format is not valid legacy format + log.W.F("fetchLegacyEvent: compact format but no event ID mapping for serial %d: %v", ser.Get(), idErr) + return nil, idErr } return UnmarshalCompactEvent(v, eventId, resolver) } diff --git a/pkg/database/serial_cache.go b/pkg/database/serial_cache.go index 9b1553c..6764cf0 100644 --- a/pkg/database/serial_cache.go +++ b/pkg/database/serial_cache.go @@ -251,7 +251,11 @@ func (d *D) GetEventIdBySerial(ser *types.Uint40) (eventId []byte, err error) { } return item.Value(func(val []byte) error { - eventId = make([]byte, len(val)) + // Validate that the stored value is exactly 32 bytes + if len(val) != 32 { + return errors.New("corrupted event ID: expected 32 bytes") + } + eventId = make([]byte, 32) copy(eventId, val) return nil }) diff --git a/pkg/version/version b/pkg/version/version index 0131a13..1a765e8 100644 --- a/pkg/version/version +++ b/pkg/version/version @@ -1 +1 @@ -v0.47.0 +v0.47.1