Skip to content

feat(ddos,bot): auto-ban floods and repeat bot offenders; fix client IP behind Cloudflare - #79

Closed
zulfff wants to merge 2 commits into
mainfrom
feat/ddos-bot-autoban
Closed

zulfff wants to merge 2 commits into
mainfrom
feat/ddos-bot-autoban

Conversation

@zulfff

@zulfff zulfff commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Description

A DDoS flood was only answered 429 and the source was never banned; bot-like traffic that was clearly not a browser was only monitored. This adds time-limited, reversible auto-banning for both, and fixes the client IP the WAF acts on behind Cloudflare.

Type of change

  • Bug fix
  • Security fix
  • New feature
  • Documentation
  • Testing

Severity

  • High

What changed

  • Auto-ban on DDoS. A per-IP flood (DDoS001) bans the source address for ddos.ban_seconds (default 10m) instead of only returning 429.
  • Auto-ban on repeat bot offenders. An address that produces bot.auto_ban_after bot-like requests within bot.auto_ban_window_sec is banned for bot.auto_ban_seconds. A missing User-Agent (BOT001) is now challenged, not just monitored.
  • Safe by construction. Loopback and trusted-proxy addresses are never auto-banned (banning a hop would lock out everyone behind it). Bans are time-limited, reversible, logged, and raise an alert.
  • Configurable: ddos.per_ip_rate / per_endpoint_rate / global_rate / ban_seconds and bot.auto_ban_after / auto_ban_window_sec / auto_ban_seconds. A negative ban value disables auto-ban. Per-IP default lowered from 100/s to 30/s.
  • Fixed a dropped ban. finalDecision now carries the ban request through even when the accumulated threat score would otherwise turn the flood into a generic challenge (which silently dropped the ban).
  • Fixed the client IP behind Cloudflare. CF-Connecting-IP is read from a trusted peer, so the WAF acts on the real visitor rather than the Cloudflare edge — rate limits, auto-bans, and the audit log are accurate again.

Checklist

  • My code follows the project style
  • I have performed a self-review
  • I have updated the documentation
  • I have added tests that prove my fix/feature works
  • go build ./... passes
  • go vet ./... passes
  • gofmt -l -s . shows no issues

Additional context

New tests cover: DDoS flood/no-false-positive/disabled, bot real-browser/repeat-offender/disabled, client-IP CF-Connecting-IP preference and spoof rejection, and an end-to-end handler test (flood → ban → BAN001). The browser fuzz suite now excludes the rate limiter, since a 19k-request harness is a flood by definition and the limiter is covered by its own tests.

Verified live: a 40-request burst through the public host auto-banned the source with DDoS001 HTTP Flood - IP for 10m and it appeared in /api/v1/bans.

FortressWAF Dev added 2 commits September 29, 2026 12:23
A per-IP flood (DDoS001) now bans the source address for ddos.ban_seconds
(default 10m), and an address that keeps producing bot-like requests is banned
too. Bans are time-limited, reversible, logged, and raise an alert; loopback and
trusted-proxy addresses are never auto-banned. The ban request survives into the
final decision — a high accumulated score used to turn a flood into a plain
challenge and drop the ban.

Missing User-Agent (BOT001) is now challenged instead of only monitored. DDoS
and bot thresholds are configurable, and a negative ban value disables auto-ban.

The client IP is read from CF-Connecting-IP when the peer is a trusted proxy, so
behind Cloudflare the WAF sees the real visitor rather than the Cloudflare edge;
rate limits, auto-bans, and the audit log are accurate.

Verified live: a 40-request burst through the public host banned the source with
"DDoS001 HTTP Flood - IP" for 10m and surfaced it in /api/v1/bans.
The API base is now the relative "/api/v1", so new URL() threw and the CSP
became "connect-src 'self' /api/v1" — a path is not a valid CSP source, so the
browser logged an error and ignored it. Only add an origin when the base is an
absolute URL; a relative base is covered by 'self'.
@zulfff zulfff closed this Sep 29, 2026
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