Cosmos Hub Restart After Neutron/Astroport Exploit: The $2.2M Sweep That Worked — and the 168,990 ATOM That Got Away

in SVM - EVM on STEEM • last month

Cosmos Hub Restart After the Neutron / Astroport Exploit

On 22–23 September 2026 the Cosmos Hub halted for about 25 hours after a Neutron governance attack drained Astroport and Drop contracts. The Hub itself was not hacked. ATOM that had already left Neutron was sitting on the attacker’s Cosmos address, so validators stopped the chain, prepared an emergency upgrade, and tried to freeze what they could.

Public reporting puts the Neutron drain at roughly $9.4–9.5 million. The attacker spent about $20,199 buying NTRN voting power, passed a proposal that seized contract admin rights via chain governance (MsgUpdateAdmin), and swept Astroport and Drop. Neutron then halted. Some funds were already off-chain or in flight. About 1.2 million ATOM was parked on Cosmos Hub. A further ~169k ATOM was queued as a THORChain refund back to the same Hub address.

That is the setup. The restart is where the story splits.

What the upgrade did get right

The Hub restarted on v28.3.0 at 10:06 pm AEST (12:00 UTC on 23 September). First block after the halt: 33,086,741.

In that block the upgrade handler moved 1,227,121.37 ATOM off the attacker’s address to:

cosmos1z8pq5cn7tdrwwzlwm0e44fgq07e43ner6vph64

Those coins were still sitting there, untouched, at the time of this write-up. At prevailing prices that is about $2.1–2.2 million the attacker did not keep. The transfer was not signed by the attacker. It was an upgrade-handler sweep. That part worked.

What did not work

10:07:38 pm AEST — block 33,086,748.
Seven blocks after the sweep, THORChain’s vault sent the refund: 168,990.898794 ATOM to the attacker’s original address.

The upgrade only moved what was on the account at block 33,086,741. Anything that landed later was outside the snapshot.

THORChain had HALTGAIACHAIN = 1, so observation of Gaia was paused. It did not have HALTSIGNINGGAIA = 1. Halting watch is not the same as halting outbound signing. When the Hub started producing blocks again, the vault refund went out. THORNode still marks the refund as “not signed” because it cannot see the Hub. The coins arrived anyway.

The address block did not hold

The plan after the sweep was supposed to be an ante-handler block on the attacker’s address. A transaction rejected in ante never reaches execution, never pays a fee, never increments sequence.

That is not what the chain shows.

10:09:29 pm — block 33,086,761.
The attacker signed a 500,000 ATOM IBC transfer to Osmosis. It was included in a block. He paid the fee. Account sequence went 8 → 9. It failed only because the amount exceeded the balance.

A working address block would never have let that transaction into a block.

3:54:58 am — block 33,090,325.
He tried again with the correct amount. It succeeded.

The refund sat on his address for 5 hours 47 minutes after the first failed IBC attempt. Both gaps were visible on-chain by 10:09 pm. There was a window of nearly six hours.

Earlier public comments that “the refund could not move because the Hub blocked the address” were wrong. The block was not enforced on that IBC path, or not applied to that address correctly. v28.3.0 source was not public at the time of this reconstruction; the ledger is.

Where the 168,990 ATOM went

On Osmosis he sold in chunks of about 20,000 ATOM between 3:58 and 4:48 am, for 266,841 USDC, average about $1.58.

Path after that:

  • 188,832 USDC via Noble and Circle CCTP to 0xe149310eB8b1b3D9C471CcD81819D393621fBA5c, swapped to ETH within minutes: +70.84 ETH
  • 50,000 ATOM to a new key first. 30,000 of it did a round trip Osmosis → Hub → Terra → Hub → Osmosis, then sold. 78,010 USDC via Axelar to 0x9bfcca13b4ac907433ac68766e96309ac867f819: 29.22 ETH, not moved on from there at last check

53 minutes from Hub credit to ETH.

Attacker wallets at last check

Ethereum:

  • 0xEF6c5A31df984c8569236a0AbC1f27580E2a5D54 — 671.0 ETH
  • 0xe149310eB8b1b3D9C471CcD81819D393621fBA5c — 94.43 ETH
  • 0x9bfcca13b4ac907433ac68766e96309ac867f819 — 29.22 ETH

New Cosmos-side keys from the same night:

  • osmo1erq7tre6nk0jfx203z8ey75g4m7yfrckl3qx87
  • cosmos1erq7tre6nk0jfx203z8ey75g4m7yfrckh2nk3v
  • terra1utez3t0nvg34d9xfswn8058kypney2c3pkx883

These are tracking addresses, not legal conclusions about every sat that ever touched them.

Two root-cause gaps

1. Sweep-at-upgrade is a snapshot, not a net.
An upgrade handler only confiscates the balance at that height. In-flight IBC, vault refunds, and delayed module sends need their own plan: halt the source, cancel the outbound, or sweep again on a later block.

2. “We blocked the address” is not proven until a real tx dies in ante.
Simulation is not enough. After restart, watch account sequence. If sequence increments, the block failed. Here it incremented on the first IBC attempt.

A third operational lesson sits with THORChain: halting a chain is not the same as halting signing for that chain. HALTGAIACHAIN and HALTSIGNINGGAIA are different switches. Only one was on.

What this was and was not

This was not a consensus bug on Cosmos Hub. It was a Neutron governance capture that turned app-level admin into chain-level admin, then a race across IBC, THORChain, Osmosis, Noble, Axelar, and Ethereum. Validators did freeze the large ATOM pile. They did not close the refund and they did not prove the blacklist under live traffic.

The 1.2M ATOM sweep is the part that should be copied. The 169k ATOM leak is the part that should be written into the next incident runbook: inventory every inbound that can still land after height H, test the ante block with a real signed transaction, and do not assume a foreign vault will stay quiet because observation is paused.

Steemit note: figures and heights above follow the on-chain reconstruction circulating after restart, cross-checked against Hub halt/restart reporting. Prices move; balances on ETH addresses should be re-checked before anyone treats them as final.