Skip to content

fix: enforce maxFilterValues on subscription and count filters - #771

Merged
cameri merged 1 commit into
mainfrom
fix/enforce-max-filter-values
Sep 12, 2026
Merged

fix: enforce maxFilterValues on subscription and count filters#771
cameri merged 1 commit into
mainfrom
fix/enforce-max-filter-values

Conversation

@phoenix-server

Copy link
Copy Markdown
Collaborator

Summary

limits.client.subscription.maxFilterValues was defined in the default settings (2500) and surfaced in the admin settings editor, but nothing read it: EventRepository.findByFilters() passed a client's authors / ids / #e / #p arrays straight into WHERE IN (...). A filter with 5,000 values was accepted and PostgreSQL had to build a hash table for it — a cheap way to spike CPU and memory per request.

Changes

  • SubscribeMessageHandler.canSubscribe (REQ) and CountMessageHandler.canCount (COUNT) now reject a filter whose array criteria hold more than maxFilterValues values in total: Too many filter values: Number of values per filter must be less than or equal to N. Zero (or unset) keeps the check disabled, matching how the neighbouring limits.client.subscription settings behave.
  • New countFilterValues() in src/utils/filter.ts sums a filter's array criteria (ids, authors, kinds, #<tag>, ...) — scalar criteria (since, until, limit, search) are not values, and are bounded by their own settings.
  • NIP-11 advertises the enforced limit as max_filter_values. NIP-11 has no field for per-filter value counts, so this is a non-standard extension; the limitation object already carries non-standard keys such as default_limit and search_supported. max_event_tags is deliberately left alone — that is NIP-11's tags-per-event field and is unrelated to this setting.
  • CONFIGURATION.md gains the missing maxFilterValues row.

Both entry points are covered because both hand client filters to the repository: REQ streams via findByFilters, COUNT via countByFilters. No other code path takes client-supplied filters.

Verification

  • pnpm run test:unit1864 passing (the pre-commit hook runs it, along with biome lint and tsc -p tsconfig.build.json, all clean).
  • New tests: REQ rejection, disabled-when-zero, exact-boundary, cross-criterion summation, scalar criteria excluded; COUNT rejection with the repository asserted not to be queried; the NIP-11 advertisement follows the setting.

One thing to flag rather than sneak in: this also renames test/unit/utils/filter.ts to filter.spec.ts, because the unit glob is test/**/*.spec.ts and its isGenericTagQuery assertions had never been running. Happy to split that out into its own PR if you prefer this one minimal.

Closes #599

Filters whose array criteria (ids, authors, kinds, #<tag>) hold more than
limits.client.subscription.maxFilterValues values in total are now rejected
with 'Too many filter values' instead of being passed to PostgreSQL as an
unbounded WHERE IN (...). The setting was defined in the default settings and
surfaced in the admin settings editor while nothing read it, so a client could
send a filter with thousands of values and make the database build a hash table
for it.

The enforced limit is also advertised in the NIP-11 limitation
object as max_filter_values, a non-standard field since NIP-11 has no field for
per-filter value counts.

Also renames test/unit/utils/filter.ts to
filter.spec.ts so its existing assertions are picked up by the unit test glob.
@changeset-bot

changeset-bot Bot commented Sep 12, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7a0cfbe

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
nostream Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coveralls

Copy link
Copy Markdown
Collaborator

Coverage Status

coverage: 72.29% (+0.06%) from 72.235% — fix/enforce-max-filter-values into main

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The reviewed changes are covered by tests and have no unresolved blocking issues.

Pull request overview

Enforces maxFilterValues for REQ and COUNT filters before repository access, while documenting and advertising the limit.

Changes:

  • Counts array-based filter values and rejects oversized filters.
  • Adds NIP-11 and configuration documentation.
  • Adds focused tests and a changeset.
File summaries
File Description
test/unit/utils/filter.ts Renamed to the executable test filename.
test/unit/utils/filter.spec.ts Tests filter-value counting.
test/unit/handlers/subscribe-message-handler.spec.ts Tests REQ enforcement.
test/unit/handlers/request-handlers/root-request-handler.spec.ts Tests NIP-11 advertisement.
test/unit/handlers/count-message-handler.spec.ts Tests COUNT enforcement.
src/utils/filter.ts Counts array-valued filter criteria.
src/handlers/subscribe-message-handler.ts Rejects oversized REQ filters.
src/handlers/request-handlers/root-request-handler.ts Advertises max_filter_values.
src/handlers/count-message-handler.ts Rejects oversized COUNT filters.
CONFIGURATION.md Documents maxFilterValues.
.changeset/enforce-max-filter-values.md Records the release change.
Review details
  • Files reviewed: 11/11 changed files
  • Comments generated: 0
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@cameri
cameri merged commit b07f9c3 into main Sep 12, 2026
20 checks passed
@cameri
cameri deleted the fix/enforce-max-filter-values branch September 12, 2026 16:03
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.

[BUG] maxFilterValues setting is advertised in NIP-11 but never enforced

4 participants