Reproduced Exploit
Subsquid — Gateway creator can steal all tokens from the GatewayRegistry
1. Stake tokens into a gateway; after unlock, unstake them. 2. Unregister the gateway — Gateway struct deleted, stakes[] kept. 3. Re-register the same peerId — totalUnstaked resets to 0. 4. Unstake again against leftover stakes[] — pulls other depositors' tokens.
Chain
Other
Category
untagged
Date
Jan 2024
Source
AuditVault
EVM Playground
Source-level debugger — step opcodes and Solidity in sync
The attack is replayed in an in-browser EVM preloaded with the exact dumped fork state. The execution tree shows every call; step by Solidity line or by opcode across all depths — source, Stack, Memory, Storage, Balances (native / ERC-20 / NFT), Transient storage and Return value stay in sync. Click a tree node, opcode, or source line to jump. No backend, no live RPC.
Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 58244-c-01-gateway-creator-can-steal-all-tokens-from-the-gatewayre. Standalone Foundry PoC and full write-up: 58244-c-01-gateway-creator-can-steal-all-tokens-from-the-gatewayre_exp in the
evm-hack-registrymirror.
Vulnerability classes: lockup · permanent · direct-drain · cross-contract-state-consistency
Reproduction: self-contained Foundry PoC with only
forge-std— no fork. output.txt · test/58244-…sol.
AuditVault taxonomy: lang/solidity · platform/pashov · severity/high · impact/loss-of-funds/direct-drain · sector/bridge · genome: lockup · permanent · direct-drain · cross-contract-state-consistency
Key info#
| Impact | HIGH — double-unstake drains other gateways' SQD from the shared registry balance |
| Protocol | Subsquid Network — GatewayRegistry |
| Vulnerable code | register resets totalUnstaked: 0 while unregister never deletes stakes[] |
| Bug class | Stale stake array / accounting reset on re-register |
| Finding | Pashov Audit Group — Subsquid · #58244 |
| Report | Subsquid-security-review.md |
| Source | AuditVault |
| Fix | delete stakes[peerIdHash] on unregister |
| Compiler | ^0.8.24 (PoC) |
| Repo | subsquid/subsquid-network-contracts commit 3545236 |
TL;DR#
- Stake tokens into a gateway; after unlock, unstake them.
- Unregister the gateway — Gateway struct deleted, stakes[] kept.
- Re-register the same peerId —
totalUnstakedresets to 0. - Unstake again against leftover stakes[] — pulls other depositors' tokens.
Vulnerable code#
gateways[peerIdHash] = Gateway({
// ...
totalStaked: 0,
totalUnstaked: 0 // @> VULN: reset without clearing stakes[]
});
// unregister deletes gateways[peerIdHash] but NOT stakes[peerIdHash]
return total - gateway.totalUnstaked; // recomputes from stale stakes
Root cause#
Two stores track the same economic reality (stakes[] amounts vs totalUnstaked). Unregister only clears one; re-register resets the other to zero, so _unstakeable overstates unlockable funds.
Preconditions#
- Operator can register/unregister a peerId.
- At least one mature stake entry exists for that peerId.
- Registry holds other users' tokens (shared ERC20 balance).
Attack walkthrough#
- Bob stakes 100 SQD; Alice stakes 100 SQD (registry = 200).
- Alice unstakes 100, unregisters, re-registers same peerId.
- Alice unstakes 100 again → registry balance 0; Alice holds 200.
Diagrams#
Impact#
Any gateway operator can drain the entire registry balance after one legitimate stake/unstake cycle on a recycled peerId.
Sources#
Sources & further analysis#
Reproductions & code
- Standalone PoC + full trace: 58244-c-01-gateway-creator-can-steal-all-tokens-from-the-gatewayre_exp (evm-hack-registry mirror).
- AuditVault finding: 58244-c-01-gateway-creator-can-steal-all-tokens-from-the-gatewayre.
Alerts & third-party analyses
These dashboards index community alerts tweets, post-mortems, and independent write-ups. Reach them through the protocol name above to cross-check this reproduction against other analyses.