Describe the bug
The relay defines limits.client.subscription.maxFilterValues (default: 2500) in settings, but this value is never checked anywhere in the codebase. A client can send a filter with 5,000+ values in authors, ids, #e, #p, etc., and the relay passes them straight to PostgreSQL as a WHERE IN (...) clause.
In EventRepository.findByFilters() (src/repositories/event-repository.ts):
builder.whereIn('event_pubkey', currentFilter.authors)
No length validation happens before this call. The setting only exists as a type definition in src/@types/settings.ts - it is never imported or read by any handler or repository.
To Reproduce
Steps to reproduce the behavior:
- Start nostream with default settings (
maxFilterValues: 2500)
- Confirm NIP-11 advertises the limit:
curl -H 'Accept: application/nostr+json' http://localhost:8008
Output includes: "max_event_tags":2500
3. Generate a filter with 5,000 authors and copy to clipboard:
python3 -c "print('[\"REQ\",\"test-bug2\",{\"authors\":['+ ','.join(['\"'+'a'*64+'\"' for _ in range(5000)]) +'],\"kinds\":[1]}]')" | pbcopy
- Connect via wscat and paste the filter:
wscat -c ws://localhost:8008
- Relay accepts and returns ["EOSE","test-bug2"] - no rejection, no error
Screenshots

- Top terminal: NIP-11 output from
curl with max_event_tags: 2500 highlighted, confirming the relay advertises a limit
- Bottom terminal:
wscat session where a filter with 5,000 authors was accepted and the relay responded with ["EOSE","test-bug2"] - no rejection
System (please complete the following information):
- OS: macOS (relay running in Docker)
- Platform: Docker Compose
- Version: 2.1.1 (d8f62b4)
Additional context
grep -rn 'maxFilterValues' src/ --include='*.ts' returns only @types/settings.ts:109 - zero enforcement anywhere
- Impact: Postgres builds a hash table for the oversized
IN clause, spiking CPU and memory. Concurrent requests like this are a straightforward DoS vector.
Describe the bug
The relay defines
limits.client.subscription.maxFilterValues(default:2500) in settings, but this value is never checked anywhere in the codebase. A client can send a filter with 5,000+ values inauthors,ids,#e,#p, etc., and the relay passes them straight to PostgreSQL as aWHERE IN (...)clause.In
EventRepository.findByFilters()(src/repositories/event-repository.ts):No length validation happens before this call. The setting only exists as a type definition in
src/@types/settings.ts- it is never imported or read by any handler or repository.To Reproduce
Steps to reproduce the behavior:
maxFilterValues: 2500)Output includes:
"max_event_tags":25003. Generate a filter with 5,000 authors and copy to clipboard:
Screenshots

curlwithmax_event_tags: 2500highlighted, confirming the relay advertises a limitwscatsession where a filter with 5,000 authors was accepted and the relay responded with["EOSE","test-bug2"]- no rejectionSystem (please complete the following information):
Additional context
grep -rn 'maxFilterValues' src/ --include='*.ts'returns only@types/settings.ts:109- zero enforcement anywhereINclause, spiking CPU and memory. Concurrent requests like this are a straightforward DoS vector.