Defending Against Circuit-Building DoS: Better Metrics, and What Tor Could Fix

By 1AEO Team • July 13, 2026 • Lessons and next steps from the June–July 2026 circuit-building DoS wave

Technical correction — October 20, 2026: Terminology and counter interpretations have been corrected. The original observation dates are retained.

Part 5 of a five-part series on the June–July 2026 circuit-building DoS.  1. The Tor Network’s Circuit-Building DoS Wave in June–July 2026 — the network-wide view from Tor's public data.  2. Anatomy of the Attack — the four observed phases in the updated reconstruction.  3. What It Actually Costs — the CPU and memory bill, and the public comparisons.  4. The Flood Below Tor — the TCP listener pressure Tor's own counters cannot see.  5. Defending Against Circuit-Building DoS (you are here) — better metrics and the protocol fixes we're asking for.

The circuit-building DoS wave hitting the Tor network made two things clear on our own guard-relay fleet: we needed to see the attack more clearly, and the durable fix belongs in the Tor protocol, not on the operator's server. This post covers both — first how we're improving our own monitoring in a way that adds zero logging and touches no personal data, then the specific things we think the Tor Project could change.

Part 1 — Seeing the Attack Without Watching the Users #

The obvious way to study an attack is to record what's arriving: capture connections, log source addresses, inspect traffic. We do not do that, and we are not going to. Everything in our companion posts — CPU, memory, onionskin queues and defense actions — comes from aggregate counters, never a packet capture or a tally of source addresses. A large distributed source pool is one possible explanation, but the counters do not establish its size, origin paths or common control. Per-source defenses have activation conditions and per-process scope, and circuits can accumulate over time below a rate limit.

Our monitoring principle is simple: measure the relay's own health and the attack's aggregate shape, never the individual source. Concretely, that means we build only on two kinds of source, both aggregate by construction:

Where we want more visibility, we get it by adding more aggregate signals, and by correlating them against public data (the CollecTor archives and Onionoo) rather than against anything we'd have to record ourselves. The gaps this wave exposed, and how we're closing them privacy-safely:

What we couldn't see wellThe privacy-safe fix
Per-relay resident-memory growthExport each relay process's resident-memory total (one gauge per relay). It's a number of bytes, not a record of anything.
Which host recorded onionskin queue-overflow drops, and whenScrape the existing onionskins_total{action="dropped"} counter per relay — and never infer drops from the Heartbeat assigned/requested gap (see Part 2), which is not a drop count.
Whether kernel memory pressure was turning into outagesWatch node_memory_MemAvailable_bytes and node_vmstat_oom_kill at the host level, alongside Tor's metrics — the OOM story is invisible to a Tor-only dashboard.
How our standing compared to the rest of the networkCorrelate our aggregate health against the public CollecTor/Onionoo record. The comparison lives in public data, so we never have to build a private one.
How large or coordinated the attacking source pool wasWe do not count or bucket source addresses. Aggregate circuit counts and rejection activity cannot determine source-pool size, whether it was distributed, or whether the same actor controlled activity across hosts.
The test we hold ourselves to: if a metric could help someone reconstruct who used the relay or what they did, we don't collect it — even to fight an attack. Retained counters describe the relay; they must never identify who is behind a connection. Fighting a DoS is not a license to start surveilling the people the relay exists to protect.

Part 2 — Measurement Traps We Hit (So You Don't Have To) #

Two metrics fooled us early, and both are easy traps for any relay operator. We publish them because the correction is more useful than the mistake.

"assigned/requested" is not "dropped" #

Tor's Heartbeat prints a line like Circuit handshake stats since last time: ... 41000/42700 NTor, .... Reading the pair as assigned/requested is correct; calling the gap "dropped onionskins" is not. In the cited Tor source, requested increments after parsing and early rejection checks; assigned increments before worker dispatch, which MetricsPort exposes as action="processed". The separate queue-admission rejection counter supplies action="dropped". All three omit channels Tor classifies as clients, including unauthenticated bridge connections. The requested-minus-assigned gap can include queue rejections, pending or abandoned work and timing effects; it does not identify the dominant cause or count successful circuit completions.

Use tor_relay_load_onionskins_total{action="dropped"} to track the recorded onionskin queue-overflow drops. The warning "Your computer is too slow to handle this many circuit creation requests." indicates queue pressure, but warning logs are rate-limited and their absence does not establish zero drops. Neither the counter nor the Heartbeat gap counts every failed or closed circuit.

The inbound-connection gauge drifts to zero between restarts #

Our inbound-connection gauge (tor_relay_connections{state="opened", direction="received"}) declined between restarts while host established-TCP counts stayed flatter. The connection-gauge investigation covers the accounting issue. Use tor_relay_connections_total{state="created"} for connection-creation activity and host TCP gauges for current connection levels; a cumulative counter is not a connection-level gauge.

Part 3 — What the Tor Project Could Change #

Circuit handshakes consume CPU and idle circuits hold memory. Tor's existing mitigations rejected work during the event, but per-source controls are not a single aggregate limit on a relay's workload. The counters do not establish how many originators supplied that workload. These are design proposals for the Tor Project to evaluate, with attention to effects on legitimate users:

We're running relays, publishing data, and comparing notes with other operators — but the durable fix belongs in the protocol. We are glad to share raw, aggregate data with Tor Project developers. Reach out.

Join the Mission