Skip to content
Docs/Platforms/OpenScrub
Edit on GitHub

OpenScrub

OpenScrub is the DDoS mitigation platform in the opensecstack (SIN) ecosystem. It delivers line-rate L3/L4 packet filtering through an XDP/eBPF kernel data plane and wraps every block decision in CITADEL-attested, WORM-anchored evidence — so NIS2 auditors can reconstruct what was blocked, why, and when without trusting a vendor log.

OpenScrub ships at v1.0.0 (2026-05-09) under the Apache 2.0 licence.

Overview

Most organisations either absorb DDoS traffic in userspace (slow) or pay for an opaque commercial scrubbing service (expensive and unauditable). OpenScrub closes both gaps:

  • Sub-microsecond drop latency. The eBPF/C program attaches at NIC ingress via XDP, before the kernel allocates an skb. A blocklist hit costs roughly 50 ns on commodity hardware — no userspace copy on the drop path.
  • Audit-grade evidence. Every distinct mitigation event emits a signed openscrub.mitigation event to the CITADEL WORM ledger, satisfying NIS2 Article 21(2)(c) incident-handling documentation requirements.
  • Automatic IOC enforcement. A built-in ThreatFlow puller pulls malicious-IP IOCs on a 15-minute cadence and reconciles them directly into the BPF blocklist map — no copy-paste, no human-in-the-loop.

Key features

ModuleDescription
XDP loader (Rust + Aya)Loads the compiled eBPF object at NIC ingress, pins BPF maps under /sys/fs/bpf/openscrub/, manages program lifecycle with CAP_BPF + CAP_NET_ADMIN + CAP_SYS_RESOURCE
eBPF/C data planePer-packet XDP_DROP / XDP_PASS decisions against an LPM-trie blocklist map and a per-CIDR rate-limit map; SYN-cookie, UDP-flood, and ICMP-flood handlers in separate programs dispatched from openscrub_kern.c
BGP blackhole (GoBGP)Embedded GoBGP speaker for Remotely Triggered Black Hole (RTBH); announces /32 or /128 host routes with RFC 7999 community 65535:666 to upstream transit providers; auto-withdraws after configurable cool-down
Go control-plane APIREST API on :8087 — rules CRUD, live mitigations, JSON metrics snapshot, Prometheus exposition; communicates with the loader over a Unix socket to maintain a privilege boundary
ThreatFlow IOC pullerGoroutine polling the ThreatFlow malicious-IP feed every 15 minutes; diffs against existing source='threatflow' rules and inserts or withdraws automatically
CITADEL evidence emitterAsync fire-and-retry emission of openscrub.mitigation events, HMAC-SHA256 signed, to the CITADEL WORM append-only ledger
Prometheus metricspps_dropped, pps_passed, rules_active, ioc_pull_latency_ms — aggregated from per-CPU BPF stats maps every second
React + Vite dashboardOperator UI on :3087; rules CRUD, live mitigation table, metrics charts; bilingual (Albanian + English)

Architecture

OpenScrub separates privilege using a Unix socket. The API process (Go, replicated) holds no kernel capabilities; it writes rules to PostgreSQL and sends RULE_INSERT / RULE_DELETE messages on /run/openscrub/dataplane.sock. The loader process (Rust + Aya, one per node) holds CAP_BPF + CAP_NET_ADMIN, owns the BPF maps, and never accepts network connections.

The block-decision data flow:

  1. An operator (or the ThreatFlow puller) creates a rule via POST /api/v1/rules.
  2. The API validates, persists the row in PostgreSQL, and messages the loader.
  3. The loader writes the CIDR into the LPM-trie blocklist BPF map (or the ratelimit map for rate-limit rules).
  4. On every incoming packet the XDP program does an O(log W) LPM lookup — hit → XDP_DROP; miss → XDP_PASS.
  5. Per-CPU stats counters are aggregated every second; a mitigation row is written and a CITADEL event is emitted asynchronously.

For volumetric attacks that exceed NIC capacity, the BGP module announces a blackhole route via GoBGP to upstream transit peers using the RTBH technique, shifting the drop point to the provider edge. The cool-down window (default 300 s) is configurable under mitigation.bgp.withdraw_delay_seconds.

Kernel attack surface: XDP map injection, rule poisoning, and loader privilege escalation are treated as critical-severity findings by default. The data plane runs privileged: false with an explicit capability set and drop: ALL as the base seccomp policy. A third-party kernel-attack-surface audit is pending scheduling.

Ports & endpoints

PortService
8087OpenScrub REST API (Go)
9091Prometheus metrics endpoint
3087React operator dashboard (nginx)
MethodPathPurpose
GET/api/v1/healthLiveness — status, version, DB ping, dataplane attached
POST/api/v1/auth/loginJWT issuance
GET/api/v1/rulesList rules (paginated; filter by type)
POST/api/v1/rulesCreate rule — type ∈ blocklist / ratelimit / syncookie
GET/api/v1/rules/{id}Rule detail
DELETE/api/v1/rules/{id}Withdraw rule and clear BPF map entry
GET/api/v1/mitigationsMitigation rows (filter by since, rule_id)
GET/api/v1/metrics/snapshotJSON metrics snapshot for the dashboard
GET/api/v1/metricsPrometheus text exposition (JWT-gated)

Integration

OpenScrub authenticates dashboard users via sinauth SSO using the OAuth 2.0 authorization_code + PKCE (S256) flow. The API validates RS256-signed tokens against the sinauth JWKS endpoint at https://auth.sin.to/.well-known/jwks.json.

Minimum required environment variables:

.env
Bash
OPENSCRUB_DB_URL=postgres://openscrub:openscrub@postgres:5432/openscrub
OPENSCRUB_DATAPLANE_SOCKET=/run/openscrub/dataplane.sock
OPENSCRUB_JWT_SECRET=<32+ random bytes>
OPENSCRUB_CITADEL_API_URL=https://citadel.internal
OPENSCRUB_CITADEL_HMAC_SECRET=<hmac secret>
OPENSCRUB_THREATFLOW_API_URL=https://threatflow.internal
OPENSCRUB_THREATFLOW_TOKEN=<bearer token>
OPENSCRUB_IFACE=eth0

Quick start with Docker Compose:

Bash
git clone https://github.com/opensecstack/opensecstack
cd opensecstack/openscrub

cp .env.example .env
docker compose -f deploy/docker-compose.yml up -d

"cm"># Health check
curl http://localhost:8087/api/v1/health

"cm"># List active rules (requires Bearer token)
curl -H "Authorization: Bearer $TOKEN" \
     http://localhost:8087/api/v1/rules

SecureLab polls GET /api/v1/alerts?technique={id}&since={ts} (read-only, HMAC-signed) to validate that OpenScrub detections fire as expected during attack simulations. ThreatFlow pushes malicious-IP IOCs inbound; CITADEL receives outbound mitigation evidence.

Full documentation

The complete OpenScrub reference — deployment guide, XDP program guide, BGP blackhole setup, API reference, CITADEL integration, and threat model — is in the repository:

github.com/opensecstack/opensecstack/tree/main/openscrub/docs

SIN — Security Intelligence Network — Open-source cybersecurity & compliance for the EU Digital Decade.

Apache-2.0 & AGPL-3.0 · GitHub · Contribute