Skip to content

Harden River invite issuance against automated spam - #83

Merged
sanity merged 1 commit into
mainfrom
invite-abuse-hardening
Jul 26, 2026
Merged

Harden River invite issuance against automated spam#83
sanity merged 1 commit into
mainfrom
invite-abuse-hardening

Conversation

@sanity

@sanity sanity commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

What changed

  • block River invitation issuance from known Tor exits
  • require a signed, short-lived, single-use SHA-256 proof-of-work challenge with adaptive difficulty
  • retain the existing per-IP limit and add a 200-invites/hour global emergency ceiling, seeded across restarts from non-Tor issuance
  • restrict invite-route browser origins while leaving unrelated API CORS behavior unchanged
  • log the generated River member ID beside the issuing IP so future bans can be correlated exactly
  • update the quickstart UI to solve proof of work invisibly, render errors cleanly, and remain compatible with the old API during rollout

Why

Automated spam waves rotated through large numbers of Tor exits, defeating the existing per-IP limit and generating hundreds of fresh River identities. Each request minted a new invitation keypair, and historical logs did not retain the member ID needed to correlate issuance with later bans.

This keeps the normal no-CAPTCHA flow while adding an immediate network block, per-request cost, replay protection, and a high-headroom final ceiling. The ceiling is calibrated above the reported 30–60 legitimate users/hour.

Closes #81.

Validation

  • cargo test -p ghostkey-api --all-targets — 40 passed, 1 network-only test ignored
  • cargo clippy -p ghostkey-api --all-targets -- -D warnings with allowances for two pre-existing lints outside this change
  • production Hugo build (hugo --gc --minify)
  • Playwright desktop and mobile success flows
  • Playwright proof replay (409), 429 retry rendering, restricted CORS, responsive overflow, and old-API rollout fallback

Observed proof-of-work completion in Chromium ranged from roughly 0.1–1.1 seconds at the base difficulty.

Rollout order

  1. Merge and wait for the new quickstart page to be live. It falls back to the old API on a 404 challenge route.
  2. Update/restart gkapi on vega.
  3. Verify /health, challenge CORS, proof issuance, Tor rejection, and member-ID logs.

This ordering avoids a signup outage and remains rollback-compatible.

@sanity
sanity marked this pull request as ready for review July 26, 2026 01:52
@sanity
sanity merged commit c0ebbf2 into main Jul 26, 2026
4 checks passed
@sanity
sanity deleted the invite-abuse-hardening branch July 26, 2026 01:52
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.

gkapi: per-IP invite rate limit is defeated by Tor circuit rotation

1 participant