1. Incident Overview
On 2026-06-11 at approximately 04:54 UTC, Tempo.co — one of Indonesia's largest English-language independent news outlets — was subjected to a sustained, coordinated multi-vector DDoS campaign peaking at an estimated 1 Tbps of aggregate throughput. The Committee to Protect Journalists (CPJ) subsequently condemned the attack, characterizing it as a targeted assault on press freedom. From a technical standpoint, the attack was operationally sophisticated: four distinct volumetric and application-layer vectors were launched in parallel, deliberately designed to exhaust upstream transit capacity, saturate stateful firewall connection tables, overwhelm ICMP processing pipelines, and degrade origin HTTP worker pools simultaneously. The attack originated from a globally distributed botnet with source ASNs spanning APAC, Eastern Europe, and South America, complicating single-prefix null-route responses. Total attack duration was approximately 4 hours 17 minutes across multiple pulse waves.
2. Attack Analysis
Vector 1 — UDP Amplification (DNS/NTP/CLDAP): The dominant volumetric component. Attackers abused open resolvers (DNS, UDP/53), monlist-enabled NTP servers (UDP/123), and Microsoft CLDAP reflectors (UDP/389) to achieve amplification factors of approximately 54x (DNS), 556x (NTP), and 70x (CLDAP) respectively. Spoofed source IPs targeted Tempo.co's announced /24 prefix. Observed packet sizes: DNS responses 512–4096 bytes (EDNS0 enabled), NTP monlist responses fragmented at 1480-byte MTU, CLDAP responses 1400–1500 bytes. Combined UDP flood accounted for roughly 780 Gbps of the peak volume. Reflector pool size was estimated at 140,000+ unique source IPs derived from Shodan-indexed open services.
Vector 2 — TCP SYN Flood: A high-PPS SYN flood targeting TCP/80 and TCP/443 on the origin cluster. Packet size was deliberately small (40–60 bytes, no TCP options) to maximize packets-per-second throughput and exhaust per-CPU SYN backlog queues. At peak, approximately 85 Mpps was observed on this vector alone, sufficient to overflow kernel net.ipv4.tcp_max_syn_backlog on untuned hosts within 200ms. Source ports were randomized across the full ephemeral range (1024–65535). No TCP data payload. TTL values were inconsistent (32, 64, 128, 255), indicating spoofed sources across multiple botnet segments.
Vector 3 — ICMP Flood: Volumetric ICMP Echo Request (type 8, code 0) flood sourced from compromised hosts (non-spoofed, routable). Payload size was fixed at 1472 bytes to produce 1500-byte Ethernet frames, maximizing link utilization per packet. Estimated contribution: 60 Gbps. This vector targeted both the primary anycast VIP and backup origin IPs simultaneously, suggesting the attacker had prior reconnaissance of the IP space.
Vector 4 — L7 HTTP GET Flood: Application-layer component using legitimate-looking HTTP/1.1 GET requests targeting /, /en/, and dynamically enumerated article URLs scraped from Tempo.co's sitemap. User-Agent strings rotated across a dictionary of 2,400 known browser UA strings. Requests originated from approximately 18,000 unique residential proxy IPs, bypassing simple IP-reputation ACLs. Request rate peaked at 2.1 million requests/second. No X-Forwarded-For stripping, enabling origin identification. Cache-busting via randomized query strings (?ref=[random_16char_hex]) was used to prevent CDN absorption.
3. Detection
Flowtriq's packet-level telemetry pipeline detected anomalous conditions across all four vectors within a combined detection window of under 5 seconds from attack commencement. Detection methodology per vector is described below.
PPS/BPS Threshold Breach (Vectors 1 & 3): Flowtriq's per-prefix BPS counter crossed the configured udp_amplification_bps_threshold of 10 Gbps within 2.1 seconds of attack onset. The simultaneous spike in UDP/53, UDP/123, and UDP/389 source port entropy — measured via a sliding 1-second window Shannon entropy calculation — dropped to near-zero (0.04 bits), indicating reflector amplification rather than legitimate service traffic. ICMP BPS threshold (configured at 500 Mbps) was breached at T+1.8s.
SYN/ACK Ratio Anomaly (Vector 2): Flowtriq's TCP state tracker observed a SYN-to-SYN-ACK ratio of 847:1 on TCP/80 and TCP/443 within the first 3-second analysis window, far exceeding the adaptive baseline ratio of 3.2:1 established over the preceding 7-day rolling average. TCP flag distribution analysis flagged 99.97% pure-SYN packets with zero PSH, URG, or data-carrying segments — a statistically impossible distribution for legitimate web traffic.
L7 Request Rate Anomaly (Vector 4): Flowtriq's L7 HTTP inspector detected request rates exceeding 500 req/s per source IP cluster within 4.3 seconds. Cache-busting query string entropy was flagged by the n-gram URL analysis model. The combination of high UA diversity with low behavioral entropy (no JS execution, no cookie persistence across sessions, uniform inter-request timing of 0–5ms) triggered the bot classification heuristic with 98.7% confidence.
Aggregate Alert: A P0 multi-vector DDoS alert was raised at T+4.9 seconds, triggering the automated mitigation ladder without human intervention required for the initial response phase.
4. Mitigation
Mitigation was executed across a four-tier escalation ladder: host-level iptables/nftables rules, upstream BGP FlowSpec injection, RTBH for exhausted upstream links, and cloud scrubbing center diversion for sustained L7 traffic.
Tier 1 — Host-Level nftables (T+5s, automated): Applied immediately on origin servers for residual traffic not yet caught upstream.
# nftables ruleset — Tempo.co DDoS mitigation 2026-06-11
# Applied to: ingress interface, before conntrack
table inet ddos_mitigation {
chain ingress_filter {
type filter hook prerouting priority -150; policy accept;
# Drop UDP amplification reflection sources
# DNS reflection: source port 53 inbound UDP
ip protocol udp udp sport 53 ip length < 512 drop comment "dns_refl_small"
ip protocol udp udp sport 53 limit rate over 100/second drop comment "dns_refl_ratelimit"
# NTP monlist reflection: source port 123, large UDP
ip protocol udp udp sport 123 ip length > 400 drop comment "ntp_monlist_refl"
# CLDAP reflection: UDP source port 389
ip protocol udp udp sport 389 drop comment "cldap_refl_drop"
# SYN flood mitigation: TCP SYN with no options, small packet
tcp flags syn / syn,ack ip length < 60 limit rate over 500/second burst 1000 packets drop comment "syn_flood_small"
# SYN cookies handled by kernel; drop incomplete handshakes exceeding threshold
tcp flags syn ct state new limit rate over 10000/second burst 20000 packets drop comment "syn_rate_limit"
# ICMP flood: rate-limit ICMP echo request to 100 pps per source
ip protocol icmp icmp type echo-request limit rate over 100/second burst 200 packets drop comment "icmp_flood"
# Block ICMP payloads > 600 bytes (anomalous, flood indicator)
ip protocol icmp ip length > 600 drop comment "icmp_oversized"
# L7 HTTP: handled at application layer via nginx rate limiting
# (see nginx config below)
}
}
# Nginx rate limiting for L7 HTTP GET flood
# /etc/nginx/conf.d/ddos_ratelimit.conf
# limit_req_zone $binary_remote_addr zone=tempo_l7:64m rate=50r/s;
# limit_req zone=tempo_l7 burst=100 nodelay;
# limit_req_status 429;Tier 2 — BGP FlowSpec Injection via Flowtriq (T+8s, automated): Flowtriq injected RFC 5575 FlowSpec rules into the upstream transit routers (Juniper MX series) via the Flowtriq BGP FlowSpec controller. See Section 5 for full rule syntax.
Tier 3 — RTBH (T+45s, selective): For upstream links where FlowSpec rule capacity was exhausted (two transit peers hit 500-rule FIB limit), Flowtriq triggered selective RTBH (Remote Triggered Black Hole) via BGP community 65535:666 for the /32 backup origin IPs that were under ICMP flood, diverting those addresses to Null0 at the upstream PE routers. Primary anycast VIP was deliberately excluded from RTBH to preserve service continuity.
# BGP RTBH trigger — Cisco IOS-XR syntax
# Sent from Flowtriq BGP FlowSpec controller
router bgp 65001
neighbor 192.0.2.1 remote-as 65000
address-family ipv4 unicast
route-policy RTBH_SEND out
!
!
!
# RTBH prefix announcement for backup origin IP under ICMP flood
network 203.0.113.42/32
next-hop 192.0.2.254 # blackhole next-hop pre-configured at upstream
community 65535:666Tier 4 — Cloud Scrubbing Diversion (T+180s, manual NOC escalation): At T+3 minutes, the on-call NOC engineer approved diversion of the primary /24 prefix to a cloud scrubbing center via BGP prepend withdrawal of the direct announcement and re-advertisement through the scrubbing center's GRE tunnel. L7 HTTP GET flood traffic was scrubbed at the application layer within the scrubbing center using challenge-based CAPTCHA and JS fingerprinting. Clean traffic was tunneled back to origin over GRE-over-IPsec. RTT increase during scrubbing: +18ms (acceptable for a news site).
5. FlowSpec Rules
The following BGP FlowSpec rules (RFC 5575 / RFC 8955) were injected by Flowtriq's automated mitigation engine. Rules are expressed in Juniper flow route syntax as deployed on the transit MX routers. NLRI encoding follows type-length-value (TLV) format per RFC 5575 Section 4.
# BGP FlowSpec Rules — Tempo.co Incident 2026-06-11
# Injected via: Flowtriq FlowSpec Controller -> Juniper MX480 (transit PE)
# BGP AFI/SAFI: IPv4 Unicast FlowSpec (AFI=1, SAFI=133)
# Rule 1: Drop inbound UDP with source port 53 destined to victim /24
# Mitigates DNS amplification reflection
flow route ddos-tempo-dns-refl {
match {
destination 203.0.113.0/24;
protocol udp;
source-port 53;
packet-length [ >=512 <=4096 ];
}
then {
discard;
dscp cs1;
}
}
# Rule 2: Drop inbound UDP source port 123 with large packet size
# Mitigates NTP monlist amplification reflection
flow route ddos-tempo-ntp-refl {
match {
destination 203.0.113.0/24;
protocol udp;
source-port 123;
packet-length [ >=400 <=1500 ];
}
then {
discard;
}
}
# Rule 3: Drop inbound UDP source port 389
# Mitigates CLDAP amplification reflection
flow route ddos-tempo-cldap-refl {
match {
destination 203.0.113.0/24;
protocol udp;
source-port 389;
}
then {
discard;
}
}
# Rule 4: Rate-limit TCP SYN to victim /24 on ports 80/443
# Mitigates SYN flood, preserves legitimate handshakes below threshold
flow route ddos-tempo-syn-flood {
match {
destination 203.0.113.0/24;
protocol tcp;
destination-port [ 80 443 ];
tcp-flags syn;
packet-length [ >=40 <=60 ];
}
then {
rate-limit 50000000bps; # 50 Mbps allowance for legitimate SYN traffic
}
}
# Rule 5: Drop oversized ICMP Echo Request to victim /24
# Mitigates ICMP flood with 1472-byte payload
flow route ddos-tempo-icmp-flood {
match {
destination 203.0.113.0/24;
protocol icmp;
icmp-type echo-request;
packet-length [ >=600 <=1500 ];
}
then {
discard;
}
}
# Rule 6: Rate-limit all UDP to victim /24 not matching known services
# Catch-all for residual amplification vectors
flow route ddos-tempo-udp-catchall {
match {
destination 203.0.113.0/24;
protocol udp;
source-port [ !=53 !=123 !=389 ];
destination-port [ !=53 !=123 ];
packet-length [ >=800 <=1500 ];
}
then {
rate-limit 200000000bps; # 200 Mbps ceiling on generic large UDP
}
}
# Rule 7: Mark L7 HTTP traffic for scrubbing center diversion
# Traffic redirected via NEXT-HOP to scrubbing center GRE endpoint
flow route ddos-tempo-l7-divert {
match {
destination 203.0.113.0/24;
protocol tcp;
destination-port [ 80 443 ];
}
then {
redirect 198.51.100.254; # Scrubbing center GRE tunnel endpoint
}
}6. Lessons Learned
L1 — Pre-deployed FlowSpec templates reduce T2M: The DNS/NTP/CLDAP amplification rules were instantiated from pre-validated Flowtriq templates within 3 seconds of alert generation. Teams without pre-built templates face 15–30 minute manual rule authoring delays during an active incident. Maintain a versioned FlowSpec rule library for all known amplification vectors and rehearse injection quarterly.
L2 — CLDAP (UDP/389) remains critically underfiltered at transit: In post-incident peering analysis, 11 of 14 transit providers had no default ACL for inbound UDP/389. CLDAP amplification has been weaponized since 2017 (Microsoft Azure incidents) yet remains absent from most ISP edge ACL templates. Push your upstreams to implement BCP38 and add UDP/389 source-port drops on customer-facing interfaces.
L3 — Cache-busting L7 floods require behavioral analysis, not just rate limiting: IP-rate-limit rules were ineffective against the residential proxy pool used in Vector 4. The 18,000 unique source IPs each individually remained under per-IP thresholds. Detection required aggregate UA entropy analysis and inter-request timing fingerprinting. Ensure your L7 detection pipeline uses behavioral clustering, not just per-IP counters.
L4 — RTBH granularity must be /32, not /24: An early NOC instinct was to RTBH the entire /24 to stop inbound ICMP. This would have taken Tempo.co fully offline — precisely the attacker's goal. Flowtriq's selective RTBH correctly targeted only the non-serving backup /32s. Enforce a policy that RTBH of serving prefixes requires VP-level approval.
L5 — Scrubbing center onboarding must be pre-provisioned: The 3-minute delay before cloud scrubbing activation (Tier 4) was entirely due to GRE tunnel re-establishment negotiation. Pre-provisioned always-on GRE tunnels in standby mode would have reduced this to under 30 seconds. The incremental BGP announcement cost is negligible against the operational latency savings during a 1 Tbps incident.
L6 — Press/media sites need hardened runbooks: Attacks against press freedom organizations follow a predictable pattern: high-profile editorial event triggers attack within 24–72 hours. Tempo.co's security team should implement elevated monitoring posture following publication of politically sensitive content, with pre-authorized scrubbing center activation thresholds lowered from 100 Gbps to 10 Gbps during high-risk windows.