Summary
On 29 and 30 May 2026, the Gravity Bridge was exploited for approximately $5.4 million through denom mapping poisoning. The attacker did not need a privileged role or a stolen key. They registered a minimal validator on Gravity with 80 GRAV, minted fake tokens on Osmosis, IBC-transferred them to Gravity, and then used the permissionless deployERC20() function on Ethereum with fabricated _cosmosDenom strings that embedded the addresses of real custody tokens. Validators acknowledged the deployment, the bridge wrote attacker-influenced metadata into its denom-to-ERC20 registry without a collision check, and a batch of withdrawals then released real assets. The stolen funds included roughly $4.3M USDC, 274 WETH, $434K USDT, and 14.16 PAXG. Validators halted the bridge once the incident was detected. An official postmortem is still pending.
What is confirmed and what is pending
Gravity issued short public statements on 30 May 2026, quoted by Rekt and others. The first: “There was an unfortunate incident on Gravity. Validators should halt their validators and orchestrators while this incident is being investigated.” The second: “Thanks to the swift action of validators, the bridge is currently halted while investigations continue.” The mechanism, loss breakdown, and on-chain artefacts below are drawn from Rekt’s technical analysis and QuillAudits’ hack analysis. A full official postmortem from the Gravity team is still pending.
Incident timeline
| Stage | Event |
|---|---|
| Setup | Attacker registers a minimal validator named julia666 on Gravity with 80 GRAV. |
| Mint | Attacker mints fake tokens on Osmosis and IBC-transfers them to Gravity. |
| Poison | Attacker calls permissionless deployERC20() on Ethereum with fabricated _cosmosDenom strings embedding real Ethereum custody token addresses. |
| Acknowledge | Gravity validators submit MsgERC20DeployedClaim; handleErc20Deployed writes attacker-influenced metadata into the denom-to-ERC20 registry without a collision check. |
| Drain | Batch withdrawals 41572–41575 are signed and submitted; safeTransfer releases real assets. |
| 30 May | Gravity instructs validators to halt; the bridge is halted while investigation continues. |
The attack path
Gravity Bridge maps Cosmos-side denominations (denoms) to Ethereum ERC-20 token addresses through a registry. When a new token is bridged, a deployERC20() call on Ethereum establishes the ERC-20 representation, and validators acknowledge that deployment back on the Cosmos side with a MsgERC20DeployedClaim. The handler handleErc20Deployed records the mapping between the Cosmos denom and the Ethereum token.
The critical weakness is that deployERC20() is permissionless and the acknowledgement path wrote attacker-influenced metadata into the registry without checking for collisions against existing, legitimate mappings. The attacker exploited this in steps that each looked individually benign.
They first registered a minimal validator, julia666, with just 80 GRAV, giving themselves standing in the validator set. They minted worthless fake tokens on Osmosis and IBC-transferred them to Gravity to create a denom they controlled. They then called deployERC20() on Ethereum with fabricated _cosmosDenom strings crafted so that the metadata embedded the contract addresses of real, valuable custody tokens such as USDC, USDT, WETH, and PAXG. When validators acknowledged these deployments through MsgERC20DeployedClaim, handleErc20Deployed wrote the poisoned mapping into the registry, with no collision check to reject a denom that pointed at an asset the bridge already held.
With the registry poisoned, the attacker triggered withdrawals. Batches 41572 through 41575 were signed and submitted, and safeTransfer dutifully released the real custody assets to the attacker’s Ethereum addresses. The bridge behaved exactly as coded; the code trusted a mapping that an unprivileged user had been allowed to write.
Technical evidence and explorer links
The following addresses, transactions, and identifiers appear in the cited analyses. Full addresses, transaction hashes, and explorer links are reproduced exactly as published.
Loss breakdown
| Asset | Amount |
|---|---|
| USDC | ~$4.3M |
| WETH | 274 WETH |
| USDT | ~$434K |
| PAXG | 14.16 PAXG |
| Total | ~$5.4M |
Confirmed vs pending
| Field | Status | Detail |
|---|---|---|
| Incident dates | Reported | 29 and 30 May 2026 |
| Bridge halt | Confirmed by Gravity | Validators instructed to halt; bridge halted while investigation continues |
| Total loss | Reported | ~$5.4M (USDC, WETH, USDT, PAXG) |
| Mechanism | Reported | Denom mapping / registry poisoning via permissionless deployERC20() |
| Missing control | Reported | handleErc20Deployed wrote registry metadata without a collision check |
| Validator abuse | Reported | Minimal validator julia666 registered with 80 GRAV |
| Official postmortem | Pending | No full postmortem published at drafting time |
Why this matters
Permissionless registration plus trusted writes is a dangerous pairing. A function being open to anyone is not a flaw in itself. It becomes one when the output of that open function is later trusted as authoritative without validation. Here, deployERC20() was permissionless by design, but the metadata it produced flowed into a registry that controlled which Ethereum token a denom could withdraw, and nothing checked whether that mapping collided with an existing legitimate asset.
Registries that control custody are part of the trust boundary. The denom-to-ERC20 map is not bookkeeping. It is the lookup that decides which real asset a withdrawal releases. Any write path into that map is effectively a write path into the vault. Treating it as configuration rather than as security-critical state is how attacker-controlled strings ended up pointing at USDC custody.
A low validator stake bar lowers the cost of an attack, not the impact. Registering a validator with 80 GRAV gave the attacker the standing needed to push the deployment claims through the validator flow. The economic cost of entry was trivial relative to the $5.4M extracted, which is the signature of a design where the value at risk is wildly out of proportion to the cost of participating.
What defenders can take from this
Validate before you trust a write to custody-controlling state. Any acknowledgement that updates a denom-to-token or asset-mapping registry must reject collisions with existing mappings and must reject denoms whose embedded metadata references custody tokens the bridge already holds. The collision check that was missing here is the single control that would have stopped the entire chain.
Separate the right to register a token from the right to define what it withdraws. A newly deployed ERC-20 representation should not be able to inherit or alias the withdrawal path of an existing, valuable asset. Bind each denom to exactly one immutable token mapping at first legitimate creation, and treat any later attempt to remap it as an attack, not an update.
Monitor the registry, not just the balances. By the time funds move in batch withdrawals, the poisoning has already happened. Alerting should fire on the registry write itself: a new mapping whose metadata references the address of a high-value custody token is a high-confidence indicator that should pause batches before they are signed.
Watch for Tornado routing as a containment trigger. The stolen funds were routed toward Tornado-associated addresses. Detecting that pattern quickly is what determines whether centralised venues and downstream protocols can react before the trail is obscured.
Sources
If you run a cross-chain bridge or any system that maps external identifiers to on-chain assets, the question is not whether your signature scheme is sound. It is whether every write into the state that controls custody is validated against collisions and bound to a single trusted origin. Security4Web3 can audit your denom and token registry logic, model the cost-to-impact ratio of your validator and registration paths, and build monitoring that pauses withdrawals the moment a registry write looks like poisoning.