333 Tor Exit Relays Became SSH Password Traps for Five Days. The Break-In Came Through the Hosts, Not Tor

333 Tor Exit Relays Became SSH Password Traps for Five Days. The Break-In Came Through the Hosts, Not Tor

Between October 1 and October 5, 2026, 377 Tor relays run by 59 different operators switched to an exit policy their operators had never configured. The new policy opened port 22. An SSH session through one of the compromised exits was redirected to one of 12 interception servers, which presented its own host key, recorded the password if the user typed one, and then logged in to the real server on the user's behalf so the session looked normal. At the peak, on October 4 at 01:00 UTC, the hijacked relays carried 7.46% of Tor's usable exit weight.

The Tor protocol was not broken. The hosts running the relays were. The only fully documented case starts with a reused password on a management VPS at Contabo and a 17-year-old OpenSSH backdoor called Ebury, and the clearest pattern in the victim list is a hosting provider: 71 of the 101 third-party relays at FranTech Solutions (the BuyVM brand, AS53667) flipped, against 13 of the 9,054 relays hosted everywhere else. A Tor exit's trustworthiness is a property of the machine and the network it sits on, which is exactly the context an IP address carries and a plain exit list throws away.

Five days from the first policy flip to an empty consensus

The first relays changed policy on October 1 at 14:49 UTC, according to the CollecTor analysis that the operator known as 1AEO posted to the tor-relays list on October 9. Forty relays belonging to 21 unrelated operators adopted the same policy inside 5 minutes and 24 seconds that afternoon, mostly through a configuration reload rather than a restart. One actor with a shell on all forty, in other words.

On the morning of October 2, the researcher who publishes as kaba opened an SSH connection through Tor and got OpenSSH's "REMOTE HOST IDENTIFICATION HAS CHANGED" banner. Rather than dismiss it, kaba ran exitmap across roughly 3,000 exits, connecting from one of their own servers to another through each of them. About a dozen served a fake host key outright. More than 300 redirected the connection to the same dozen interception servers. Kaba sent the findings to the Tor network health team that evening; the write-up puts the total at 333 compromised exits.

Directory authorities started voting BadExit and MiddleOnly on October 4 at 18:00 UTC, and the flags were in the consensus by 21:00. By 17:00 UTC on October 5 not a single relay carrying the attacker's policy remained listed. That same morning a scripted restart swept 253 Quetzalcoatl relays on 70 hosts while the rogue policy was still in place. Nobody has said who ran it.

Oct 1 Oct 2 Oct 3 Oct 4 Oct 5 Oct 6 Oct 7 Oct 8 Oct 9 Oct 1, 15:34 UTC 40 relays at 21 operators flip in 5 min 24 s Oct 4, 01:00 peak: 351 relays, 7.46% of exit weight Oct 5, 17:00 no flipped relay left in the consensus Oct 9 41 relays still publish the policy, all unlisted Oct 2, 09:34 Quetzalcoatl exits publish it; kaba finds 333 exits, 12 servers Oct 4, 18:00 BadExit votes start, consensus at 21:00 Oct 7 operator post-mortem: Ebury 1.8.3, reused password relays with the attacker's exit policy in the consensus, Oct 1 14:49 to Oct 5 17:00 UTC
The hijack from first policy flip to cleanup. Times are UTC, from the 1AEO CollecTor analysis, kaba's write-up and the Quetzalcoatl post-mortem.

A working login that was not yours

On each compromised host, a NAT rule caught outbound connections to port 22 and sent them to one of the 12 interceptors, which completed the SSH handshake with its own ED25519 key (SHA256:6baCZCPsl+AfQuujUS81fMEE/C7UeJ+AwjrImqmDB3E, if you want to grep your known_hosts). A returning user saw the changed-key warning. A first-time user saw the ordinary "are you sure you want to continue connecting" prompt, which almost everyone answers yes to. To be fair to the victims, the warning did fire. But anyone who has rebuilt a VPS knows how routinely that banner is waved through.

If the user then typed a password, the interceptor had it in clear text. It opened a second SSH connection to the real server with that password, relayed the shell back, and watched every command. Kaba's honeypot captured what came next: a client built on the Python library Paramiko checked for sudo rights and ran a base64-encoded Perl installer that drops Ebury. The user saw a working login. The server was now part of the botnet.

Public-key authentication broke this chain, and it is worth being precise about why. The signature an SSH client sends during publickey authentication covers the session identifier, a hash derived from the key exchange of that specific connection (RFC 4252, section 7). The interceptor's session with the client and its session with the real server have different identifiers, so the client's signature is useless on the second leg. The interceptor could still accept the login itself and show a fake shell, but it could not reach your machine with it.

Tor client Hijacked exit relay Interception server Your server ssh user@server, port 22 port 22 redirected by NAT attacker's host key offered host key warning, user types yes password sent, captured in clear logs in with the password shell relayed back, every command watched, Ebury installed with public-key auth instead signature covers the session ID replay fails, RFC 4252
Where the interception works and where it stops. The password leg hands the attacker a reusable credential. The public-key leg does not, because the signature is bound to one connection's session identifier.

Who got hit tracks the hosting provider, not the relay software

The largest affected group was the Quetzalcoatl family: every one of the 273 relays it had listed on October 1, spread over 7 autonomous systems, flipped. Its operator, who signs as Zimmer, published a post-mortem on October 7 that is unusually candid. On August 28 at 03:19 UTC, more than a month before any relay changed, someone logged in to the family's management server, a Contabo VPS that doubled as WireGuard gateway and SSH jump host, from 185.225.226.62 (VikHost, AS207560). They used the operator's password, and it worked on the first try. Five minutes later they had root. An hour after that, a FranTech VPS called Switzerland2 that ran two exits accepted a login with an RSA key that was in none of its authorized_keys files, and Ebury 1.8.3 was installed there one second later.

"The root cause was ours," Zimmer wrote: one password reused for SSH login, sudo and the backup passphrase, stored in plaintext on both servers, with password authentication left enabled on an internet-facing host. The family's "offline" master keys sat in a workstation backup on that same server, encrypted with the password the attacker already had. On Switzerland2, the torrc rewrite came on October 2 at 09:34 UTC and the open policy ran for about 52 hours on two Guard+Exit relays moving roughly 3.4 TiB a day. Zimmer retired every relay in the family, 168 by Onionoo's count on October 6, and deleted both servers.

That explains one family. It does not explain the other 58 operators, and this is where the hosting pattern appears. Of the relays listed in the consensus on October 1 at 14:00 UTC and not belonging to Quetzalcoatl, 71 of the 101 at FranTech switched policy. Only 13 of the 9,054 hosted anywhere else did. Kaba counted it from the other direction: in kaba's October 2 scan, 26 of the 27 compromised servers outside the Quetzalcoatl family were BuyVM machines. Across all 377 affected relays, 129, or 34.2%, sit in AS53667.

Nobody has shown that FranTech itself was breached, and the analysis is careful to say so: whether the access "came from one shared hole or from earlier break-ins is not in the data". BuyVM is unusually welcoming to exit operators, which inflates any raw count, but a 70% hit rate against 0.14% is not explained by popularity. Marc-Etienne Léveillé, who has followed Ebury for 13 years and wrote ESET's 2024 report on it, added on the list that a compromised hosting provider is one possibility: ESET "identified a couple of them in the past" whose management servers ran Ebury and whose customers' VPSes "ended up running Ebury as well". Whether FranTech is one of those cases is open, and the provider has not published anything.

Here is what the exit population looks like by network this week. We pulled the running relays with the Exit flag from Onionoo at 22:00 UTC on October 22: 2,714 exits across 195 autonomous systems, with the top ten networks holding 73% of them. Most of those are dedicated exit operators announcing their own AS, several of them non-profits such as the Church of Cyberology or DFRI, not commodity VPS providers. FranTech is down to 20 running exits. On October 1 it had 149 relays in the consensus, exits and middle relays together.

Running relays with the Exit flag by AS, Onionoo, 2026-10-22 22:00 UTC (2,714 exits, 195 ASes) Quintex Alliance Consulting Church of Cyberology Stiftung Erneuerbare Freiheit DFRI Unredacted Foundation for Applied Privacy Emerald Onion Fourplex Telecom Gigahost FlokiNET AS62744 AS215125 AS60729 AS198093 AS401401 AS208323 AS396507 AS27284 AS56655 AS200651 593 (21.8%) 476 (17.5%) 255 (9.4%) 148 (5.5%) 123 (4.5%) 120 (4.4%) 95 (3.5%) 82 (3.0%) 46 (1.7%) 45 (1.7%) FranTech Solutions (BuyVM) AS53667 20 (0.7%) 101 relays were listed there on Oct 1, 14:00 UTC
Where Tor's exits live, by relay count rather than consensus weight. Top ten networks plus FranTech, the provider at the center of this incident. Source: Onionoo, 2026-10-22.

Concentration cuts both ways. A dedicated exit operator with its own AS is a single point of failure, but it is also one organization with one security posture. A commodity VPS provider hosting a hundred exits for dozens of unrelated customers is a different animal: one compromised management server, and the exits of strangers flip together. That is what the October data looks like.

An exit list is a snapshot of an hourly consensus

The detail that should worry anyone running Tor detection off a static list is this: 24 of the 377 affected relays had not been exits before. They were middle relays until the attacker turned them into exits on October 2 and 3, and all 24 received the Exit flag. A bulk exit list downloaded on September 30 did not contain them. For the days they carried traffic, those 24 addresses were Tor exits to every destination they reached and invisible to every stale list.

Tor's directory authorities publish a new consensus every hour, and the Exit flag is recomputed each time from the relay's published policy. The count does not sit still even in a quiet month. Tor Metrics shows 3,207 relays with the Exit flag on September 20, 3,013 on October 4, and 2,715 on October 5 after the BadExit sweep. On October 20 the count was 2,652, still more than 400 below the October 1 to 3 level. Onionoo also lists 132 running exits first seen since October 1, so addresses are joining as well as leaving.

3,200 3,000 2,800 2,600 Sep 20 Sep 27 Oct 4 Oct 11 Oct 18 Oct 1: policy flips start Oct 4 to Oct 5: 3,013 to 2,715 BadExit sweep removes the flipped relays 2,652 on Oct 20 Source: metrics.torproject.org, relays by flag, Exit
Relays carrying the Exit flag, September 20 to October 20, 2026. The step on October 5 is the BadExit and MiddleOnly sweep; the count has not recovered.

So the answer to "is this IP a Tor exit" has a timestamp on it, and it is only good for about an hour. We wrote about the mechanics of detecting Tor users a while ago; the update after this month is that the check has to be re-evaluated against the current consensus, with the hosting network attached to the answer. A list refreshed daily would have called the 24 new exits ordinary hosting traffic for up to a day. A consensus-only check has the opposite blind spot: on October 9, 41 relays still advertised the rogue policy but had been dropped from the consensus, so the check says "not Tor" about a host that is demonstrably still compromised. The hosting network and the address's recent history tell those two cases apart.

What to do now

If you opened an SSH session through Tor between October 1 and the afternoon of October 5, accepted a host key you did not recognize, and typed a password, treat that password as stolen. Change it and check the server for Ebury. The indicators from the post-mortem are specific: a setuid file at /usr/lib/x86_64-linux-gnu/libkeyutils.so.1.10.2 that no package owns, with the libkeyutils.so.1 symlink re-pointed to it, an abstract UNIX socket named @event-0YsOG9WSOE, and a process posing as /sbin/rsyslogd inside the ssh.service cgroup. Package integrity checks pass, because the implant sits beside the real library. Run any check from a shell with the userland rootkit disarmed, or better, from a rescue system:

H=1 I=1 LD_PRELOAD=":" LD_DEBUG=":" bash
ls -la /usr/lib/x86_64-linux-gnu/libkeyutils.so*
ss -xlp | grep '@event-'
dpkg -S /usr/lib/x86_64-linux-gnu/libkeyutils.so.1.10.2

Léveillé has an updated detection script that covers 1.8.3 on the ebury_update branch of a personal copy of ESET's malware research repository, since ESET's published version predates this variant. For SSH over Tor generally: keys only, PasswordAuthentication no on the server, and pin the host key before you go through an anonymity network rather than trusting the first answer at the far end. The host key check is the only thing standing between an SSH client and an impostor, and it is advisory.

Relay operators got a checklist from the Tor Project's network health team on October 5: look for an Exit flag or policy you did not set, diff torrc and any included files, dump the NAT table for anything touching port 22, and look for unknown listeners, new users, authorized_keys entries, cron jobs and systemd units. If anything is off, reinstall rather than clean, generate a new relay identity, rotate every credential the host ever saw, and write to [email protected], including to get an IP unblocked once the machine is rebuilt. The checklist is short. The reinstall is the part people skip.

Ipregistry's security fields report is_tor and is_tor_exit for every lookup alongside the connection's ASN and organization, so a yes on the exit flag arrives with the hosting network attached, which this incident showed matters as much as the flag itself. You can try the API with 20,000 free lookups to get started.

Engage customers with in-app updates using Noticeable Keep users in the loop Ship release notes that get read. Try Noticeable

Get started with 20,000 free lookups: sign up