Skip to content

Harden public report capacity without evicting active security budgets #41

Open

Description

@DysektAI

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions