Skip to content

Flag submission rate limiting with admin WebSocket alerts - #15

Open
dgoulet wants to merge 2 commits into
nsec:mainfrom
dgoulet:team-rlimit
Open

Flag submission rate limiting with admin WebSocket alerts#15
dgoulet wants to merge 2 commits into
nsec:mainfrom
dgoulet:team-rlimit

Conversation

@dgoulet

@dgoulet dgoulet commented May 17, 2026

Copy link
Copy Markdown

A per-team token-bucket rate limiter sits in front of the flag submission handler. When a team exhausts their token
bucket, they receive HTTP 429 responses for the duration of a configurable grace period. The limiter tracks four
states to minimize event noise:

  • Allowed — normal submission, proceeds as usual
  • FirstBreach — bucket just emptied; emits a blocked WebSocket event and starts the grace period
  • Blocked — team is in the grace period; silently rejects with 429
  • Unblocked — grace period has expired on this request; emits an unblocked WebSocket event and allows the submission
    through

Rate and burst default to 5 req/s and a burst of 10 so the limiter works out of the box, but all three parameters
are in the live-reloadable config section so they can be tuned during an event without a server restart.

New config section (api/config.go)

rate_limit:
rate: 5.0 # tokens refilled per second (default: 5)
burst: 10.0 # max burst before tripping (default: 10)
grace_period: 5.0 # minutes blocked after first breach (required to enable)

Rate limiting is disabled when grace_period is not set, so existing deployments are unaffected.

EventRateLimit is emitted on the existing flags admin channel with type: "blocked" or "unblocked", so any existing
flag monitor clients receive these events without needing to subscribe to a new channel.

Admin hook command (cmd/askgod)

askgod admin monitor-hook --event ratelimit /path/to/script.sh

Connects to the requested event channels and invokes the given script for every matching event, with the full event
JSON on stdin. Multiple event types can be combined (--event ratelimit,flags).

David Goulet added 2 commits May 17, 2026 11:18
The database config now has a new section:

  rate_limit:
    grace_period: 5.0  # minutes — required to activate
    # rate: 5.0        # default
    # burst: 10.0      # default

Once a team is detected to breach the limit, a websocket admin "blocked"
event is emitted. It is unblocked, once the grace period is over, a
"unblocked" event is emitted for that team.

Signed-off-by: David Goulet <dgoulet@riseup.net>
This allows to hook a script to a specific websocket event:

  askgod admin monitor-hook --event ratelimit /path/to/ban.sh
  askgod admin monitor-hook --event ratelimit,flags /path/to/handler.sh

The script receives the full event JSON on stdin for every matching event:

  {
    "server": "askgod",
    "type": "flags",
    "timestamp": "...",
    "metadata": {
      "team": { "id": 3, "name": "TeamFoo", ... },
      "type": "blocked"
    }
  }

Signed-off-by: David Goulet <dgoulet@riseup.net>
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