Internet shutdowns are not always BGP withdrawals. Iran has repeatedly run what Aryapour (2025) calls a stealth blackout: leave BGP routes up so the world doesn't see a country fall off the map, but throttle DNS / HTTP / HTTPS below usable thresholds. Looks like a country with normal connectivity on the BGP control plane; users inside can't load anything.
Voidly's forecast uses IODA BGP alerts as a feature. That means stealth blackouts are systematically under-predicted: the BGP data they rely on says everything's fine.
The detection heuristic
- Rule 1: IODA
ping-slash24critical alerts ≥ 5 in a country-day (active-probing disruption) - Rule 2: IODA
bgpcritical alerts <ping-slash24 × 0.5(BGP relatively stable) - Rule 3: Strength boosted by OONI blocking / interference / middlebox-detection ≥ 0.4 mean value
What we found (30-day window)
- 458 candidate country-days total
- 149 strong candidates (strength ≥ 0.7)
- 191 unique countries flagged
- Iran: 15/15 candidates strong with strength=1.0
Iran's pattern is textbook Aryapour: 2026-05-13 → 2026-05-18, six consecutive days with ping-slash24 critical alerts (84-221/day), BGP critical alerts at 0, and OONI blocking signal ~0.43-0.85 across 5-11 measurements per day.
The unexpected win: back-classification
Of the 458 candidates, 0 are novel — every
single one is already in our incidents table. But they're
all stored with mechanism = NULL, titled
generically “Internet connectivity disruption in country X.”
The detector gives us a way to back-classify those opaque incidents as “stealth blackout / data-plane only” rather than treating them as ordinary outages. That's the unexpected research-grade win — not finding novel events, but characterizing the ones we already know about.
Top countries flagged
| Country | Candidate days |
|---|---|
| VE Venezuela | 24 |
| EG Egypt | 18 |
| IN India | 15 |
| IR Iran | 15 |
| PA Panama | 12 |
| TT Trinidad & Tobago | 12 |
| SI Slovenia | 11 |
| ZW Zimbabwe | 9 |
| AO Angola | 8 |
| BA Bosnia & Herzegovina | 8 |
Caveats — what the detector misses
- One noisy day (2026-05-03) flagged 100+ countries simultaneously — almost certainly an IODA-side sensor blip, not a synchronized global stealth blackout. Need a global-blip filter before promoting.
- No probe latency baseline per country-day: our probe_metrics table only has 1 day of history. Throttling at the probe layer is invisible to current sensors.
- Probes concentrated outside censoring countries. Almost zero internal vantage in IR/CN/RU. Stealth detection from outside is structurally hard.
- No throughput sampling. Pure-throttling stealth blackouts (no packet loss but reduced bandwidth) won't register on ping-slash24.
Recommended new sensors (long-term)
- Internal vantage probes inside IR/CN/RU (high-risk co-op recruitment)
- Per-domain throughput sampling (TCP segment-rate, TLS handshake duration)
- Anycast latency telemetry from CDN partners (Cloudflare RAT, Fastly)
- RIPE Atlas ping-anchor diff between control plane (BGP) and data plane (ICMP)
What ships today
GET /v1/sentinel/stealth-blackouts returns the
candidate list with reasoning, evidence permalinks, matched
existing incident IDs, and the documented data gaps. Filter
by country, label (candidate / strong_candidate / weak),
since, limit.
Marked research_notice: not promoted to production
in the response. Forecast feature integration deferred until
the global-blip filter lands.
Files: scripts/stealth-blackout-detector.py (heuristic +
candidate generator), scripts/patch-stealth-blackout-endpoint.py
(atomic Flask route patcher).