Repository navigation
Harden public report capacity without evicting active security budgets #41
Description
Confirmed limitation
The public report policy intentionally caps process-local state at 10,000 client keys and fails closed for new clients at capacity. An unauthenticated sender controlling enough genuine IP addresses or IPv6 /56 prefixes can keep those entries active and deny admission to other clients. Spoofed forwarding headers can also fill the table if the deployment proxy does not overwrite them; the actual proxy boundary remains unverified.
PR #38 now reclaims expired state at most once per second while at capacity and has regression coverage proving that expired attempt-only state is reclaimed without losing report holds. It deliberately does not evict still-active attempt-only entries: doing so permits rotating keys to reset the five-attempt rolling-minute budget. An in-memory mutation implementing that suggested eviction fails the new budget-preservation test.
Remaining work
- Verify the actual single-hop proxy path, forwarding-header sanitation and origin isolation; do not blindly change
trust proxy = 1. - Establish operator-side multi-key abuse protection and legitimate intake capacity requirements.
- If stronger guarantees are required across processes/restarts, choose an operator-approved shared/persistent limiter and a bounded admission design that preserves all active security budgets.
Do not solve this by removing the cap, trusting arbitrary forwarding headers, evicting active allowances or weakening the attempt limit. Hosting/infra changes require operator approval and access.
Expiry-aware sweep follow-up
The post-push P3 review on PR #38 identified the cost of sweeping a full active table once per second. This is reproducible: on local Node 24.21.0, 30 samples with 10,000 clients holding 20 report events each measured 1.95 ms mean / 4.56 ms maximum per at-capacity admission, compared with 0.01 ms mean / 0.14 ms maximum using the original one-minute schedule during the same no-expiry interval. These are local microbenchmark results, not production measurements.
The one-second throttle bounds this work and promptly reclaims genuinely expired slots; reverting it restores the expired-capacity admission bug. A follow-up should track the earliest eligible expiry or use an expiry-aware index, preserving pending reservations, uncertain delivery, active report allowances and active attempt budgets. Add a deterministic regression showing no full-table scan during an interval when nothing can expire, plus the existing exact-boundary and capacity-safety tests. This low-priority optimization remains deferred rather than changing the limiter architecture in another readiness-fix round.
Review thread: #38 (comment)
Handoff
The current implementation is on fix/report-limits-errors in /home/lab/TrackerBot-pr38; dependencies are isolated on fix/deps-follow-redirects-1-16-1 and fix/deps-ip-address-10-7-4. Relevant regression: node --test test/report-policy.test.js. No production settings or data were mutated.
Activity