Skip to content

fix(pagination): enforce bounded page size on sensitive list/export endpoints (SB-C02) - #1287

Merged
groupsky merged 1 commit into
masterfrom
fix/sb-c02-pagination-limits
Jul 11, 2026
Merged

fix(pagination): enforce bounded page size on sensitive list/export endpoints (SB-C02)#1287
groupsky merged 1 commit into
masterfrom
fix/sb-c02-pagination-limits

Conversation

@groupsky

@groupsky groupsky commented Jul 11, 2026

Copy link
Copy Markdown
Member

SB-C02 · Unbounded pagination (Critical)

Problem

List/export endpoints let a single authenticated request pull an unbounded number of full records — sensitive-species exact coordinates, confidential records, and observer PII included. The -1 "unlimited" sentinel mapped to 20,000/50,000 (or truly unbounded), positive limits were honored verbatim with no ceiling, and un-floored Math.min caps let limit=-1 slip past intended limits (even dropping the LIMIT clause entirely on user:list).

Fix

Centralised, floor-then-cap pagination with hard server-side ceilings that apply to every role and input:

  • config/pagination.jsformListMax 1000, formExportMax 50000, userListMax 5000, zoneListMax 50000, alertListMax 500, publicMax 1000.
  • helpers/pagination.jsresolveLimit (-1/negative → bounded max, never unbounded or the accidental →1 collapse), clampLimit (floor-then-cap), clampOffset.
  • initializers/formMethods.js<form>:listformListMax; <form>:exportformExportMax threaded via a new opts.max; public-context clamp preserved.
  • initializers/formActions.js — strip limit/offset before count() so pagination totals stay true.
  • actions/user.js, actions/zones.js (was fully unbounded — no limit applied), actions/suspiciousActivityAlerts.js — now bounded.
  • helpers/auditHelpers.jsvalidatePagination delegates to the shared helpers (dedup; existing tests are the regression guard).

Reference-data endpoints (helpers/paging.js consumers: location:*, ebp:speciesList, nomenclature:*) are intentionally out of scope — clients rely on their full-list -1 default; they need a separate client-pagination / static-JSON / permissioned-storage migration.

Testing

  • New Postgres-only tests (__tests__/helpers/pagination.js, __tests__/actions/pagination.js): helper units + list/export/user/zone/alert clamp and count-integrity assertions, including the -1 → max (not 1, not unbounded) property.
  • Full suite run on SQLite + Postgres. All pagination-affected suites pass; the only failures are pre-existing/environmental and unrelated to this change: test/banner.js (locale/banner rendering, fails identically on master) and __tests__/initializers/filestorage.js (heif-convert binary absent locally; CI provides it).
  • standard lint clean.

Android is unaffected (forms are POST; no user:list). Exports remain bounded (50000 = prior admin ceiling); chunking/approval of very large exports is deferred to the SB-C05/SB-C03 work.

…ndpoints

SB-C02: unbounded pagination let a single authenticated request pull up to
50,000 full records (sensitive-species coordinates, confidential records,
observer PII). The `-1` "unlimited" sentinel and un-floored `Math.min` caps
allowed unbounded or negative limits to reach the database.

- Add config/pagination.js with hard ceilings (formListMax 1000,
  formExportMax 50000, userListMax 5000, zoneListMax 50000, alertListMax 500,
  publicMax 1000).
- Add helpers/pagination.js: resolveLimit (-1/negative -> bounded max, never
  unbounded), clampLimit (floor-then-cap), clampOffset.
- formMethods: <form>:list -> formListMax; <form>:export -> formExportMax via
  a threaded opts.max; public-context clamp preserved.
- formActions: strip limit/offset before count() so totals stay true.
- user:list, zone:list (previously fully unbounded), and
  suspiciousActivityAlert:list now bounded.
- auditHelpers.validatePagination delegates to the shared helpers (dedup).
- Tests (Postgres-only): helper units plus list/export/user/zone/alert clamp
  and count-integrity assertions.

Reference-data endpoints (helpers/paging.js consumers) left untouched by
design; client-side follow-ups tracked in code6x/bspb#57 and code6x/bspb#58.

Refs code6x/bspb#1
Claude-Session: https://claude.ai/code/session_018gAWWqf9usV6Wb7ERB4xNY
@groupsky
groupsky force-pushed the fix/sb-c02-pagination-limits branch from 594bd30 to cf88a2e Compare July 11, 2026 19:23
@groupsky
groupsky merged commit 30f87b3 into master Jul 11, 2026
11 checks passed
@groupsky
groupsky deleted the fix/sb-c02-pagination-limits branch July 11, 2026 21:11
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.

1 participant