All incidents

EHIVE Reward Inflation

Share
Jul 14, 2023 08:24 UTCAttackLoss: 27.33 WETHPending manual check2 exploit txWindow: 37d 23h
Estimated Impact
27.33 WETH
Label
Attack
Exploit Tx
2
Addresses
2
Attack Window
37d 23h
Jul 14, 2023 08:24 UTC → Aug 21, 2023 07:44 UTC

Exploit Transactions

TX 1Ethereum
0xd9156f507c701a09d3312e1987383c7c882df50b3127e1adfd74d74052642114
Jul 14, 2023 08:24 UTCExplorer
TX 2Ethereum
0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c1
Aug 21, 2023 07:44 UTCExplorer

Victim Addresses

0x4ae2cd1f5b8806a973953b76f9ce6d5fab9cdcfdEthereum
0xae851769593ac6048d36bc123700649827659a82Ethereum

Loss Breakdown

27.33WETH

Similar Incidents

Root Cause Analysis

EHIVE Reward Inflation

1. Incident Overview TL;DR

EHIVE was exploited on Ethereum through a deterministic staking-accounting flaw. In the priming transaction 0xd9156f507c701a09d3312e1987383c7c882df50b3127e1adfd74d74052642114, attacker EOA 0x0195448a9c4adeaf27002c6051c949f3c3234bb5 deployed an exploit system and registered many helper contracts as EHIVE stakers with stake(0, 0), creating old staking start timestamps without committing principal. In the profit transaction 0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c1, the attacker flash-borrowed 18 WETH, bought EHIVE, pushed EHIVE through the helpers, and each helper minted retroactive rewards by staking a fresh balance and immediately unstaking. The inflated EHIVE was then sold into the EHIVE/WETH Uniswap V2 pair, and the exploit contract transferred 9.320314393658547376 WETH to the attacker EOA. After the attacker EOA's gas spend of 0.075088488789763092 ETH, the cluster remained net positive by 9.245225904868784284 ETH-equivalent.

The root cause is that EHIVE computes accrued rewards after increasing the stored stake balance. Newly deposited stake therefore inherits the full historical accrual window of the old position, which violates the expected staking invariant and enables deterministic token inflation.

2. Key Background

EHIVE at 0x4ae2cd1f5b8806a973953b76f9ce6d5fab9cdcfd is both an ERC20 token and the staking contract. Its staking subsystem tracks per-staker state including a start timestamp, staked principal, and earned rewards. Reward accrual depends on elapsed time and the currently stored stake amount, so correctness depends on updating accrued rewards before mutating principal.

The exploit also depends on a live liquidation venue. The EHIVE/WETH Uniswap V2 pair at 0xae851769593ac6048d36bc123700649827659a82 supplied that venue. The execution trace for the profit transaction shows the pair paying out 27.329314393658547376 WETH during the final swap, which is the liquidity drain that converts inflated EHIVE into a realizable asset.

The ACT framing is supported by the execution environment. EHIVE staking is public while staking is enabled, validator index 0 exists, and the attacker only needs permissionless building blocks: arbitrary contract deployment, public EHIVE staking functions, a public flash-loan source, and a public AMM liquidation path.

3. Vulnerability Analysis & Root Cause Summary

The vulnerability is a state-accounting bug in EHIVE staking. In the verified EHIVE source, _userEarned reads the staker's current staked amount and old start timestamp to compute rewards. However, for an already registered staker, stake(uint256 stakeAmount, uint256 validator) first executes _stakers[msg.sender][validator].staked += stakeAmount, then adds _userEarned(msg.sender, validator), and only after that resets start = block.timestamp.

function _userEarned(address staker, uint256 validator) private view returns (uint256) {
    uint256 staked = userStaked(staker, validator);
    uint256 stakersStartInSeconds = _stakers[staker][validator].start.div(1 seconds);
    uint256 blockTimestampInSeconds = block.timestamp.div(1 seconds);
    uint256 secondsStaked = blockTimestampInSeconds.sub(stakersStartInSeconds);
    uint256 earn = staked.mul(apr).div(100);
    uint256 rewardPerSec = earn.div(365).div(24).div(60).div(60);
    return rewardPerSec.mul(secondsStaked);
}

function stake(uint256 stakeAmount, uint256 validator) external isStakingEnabled {
    if (isStaking(msg.sender, validator)) {
        _stakers[msg.sender][validator].staked += stakeAmount;
        _stakers[msg.sender][validator].earned += _userEarned(msg.sender, validator);
        _stakers[msg.sender][validator].start = block.timestamp;
    }
}

This ordering violates the intended invariant: when an existing staker adds new principal, only the old principal may earn rewards for elapsed time before the top-up, while the newly added principal must start accruing from the new timestamp. Instead, the entire post-top-up balance is treated as if it had been staked since the old start time.

The bug becomes exploitable because unstake(uint256 validator) immediately mints back principal plus userEarned(msg.sender, validator):

function unstake(uint256 validator) external {
    uint256 reward = userEarned(msg.sender, validator);
    if (totalSupply().add(reward) < maxSupply && stakingEnabled) {
        _mint(msg.sender, _stakers[msg.sender][validator].staked.add(reward));
    } else {
        _mint(msg.sender, _stakers[msg.sender][validator].staked);
    }
    delete _stakers[msg.sender][validator];
}

That means a staker with an old timestamp can deposit fresh EHIVE and immediately withdraw more EHIVE than was deposited, without any new waiting period. The analysis therefore correctly categorizes the case as an ATTACK: a broken staking invariant causes deterministic inflation, and the final liquidation into WETH is only the realization step.

4. Detailed Root Cause Analysis

The exploit pre-state is Ethereum mainnet immediately before block 17961696, after the attacker had already primed helper contracts in block 17690498. The priming transaction happened at 2023-07-14 08:24:59 UTC, and the profit transaction happened at 2023-08-21 07:44:59 UTC, so the attacker had roughly 38 days of historical reward time available to reuse.

The priming trace shows repeated zero-value staking calls through helper contracts:

0x457CaD33261e3B159D27Ffcc2Ca661702EF5E1AE::stake(0)
  EHIVE::stake(0, 0)
...
0x997b505c5f0bf9c65795B3b5e3fC5749908C8F8A::stake(0)
  EHIVE::stake(0, 0)

Those calls are enough to register the helpers as stakers because the EHIVE stake function writes a Staker(msg.sender, block.timestamp, stakeAmount, 0) record even when stakeAmount is zero. The trace also shows storage writes that set each helper's start field to the transaction timestamp while burning zero tokens.

In the second transaction, the attacker exploited the stale timestamps. The trace shows repeated helper round trips of the form:

EHIVE::stake(522013248842547733718374360879, 0)
EHIVE::unstake(0)
EHIVE::transfer(0x36A7cAA67695508aF05e9eCCF90264d2bf24d96A, 549166677730209938893144958479)

This pattern is the code-level manifestation of the bug. Each helper receives a fresh EHIVE balance, calls stake(balance, 0), and immediately calls unstake(0). Because stake already increased staked before _userEarned runs, the reward calculation uses the fresh principal together with the old primed timestamp. The helper therefore exits with more EHIVE than it entered with and forwards the inflated balance to the next helper, compounding the effect across the chain.

The final liquidation is also explicit in the trace:

EHIVE::transfer(UniswapV2Pair: [0xAE851769593AC6048D36BC123700649827659A82], 744457804386369638928651842479)
UniswapV2Pair::swap(0, 27329314393658547376, 0x98C2e1E85F8bF737D9c1450dd26D4A4bf880B892, 0x)
WETH9::transfer(0x98C2e1E85F8bF737D9c1450dd26D4A4bf880B892, 27329314393658547376)
...
WETH9::transfer(0x0195448a9c4ADEaF27002C6051C949f3C3234bb5, 9320314393658547376)

The balance diff independently confirms the outcome. The Uniswap pair lost WETH, EHIVE balances and EHIVE supply increased materially, and the exploit contract ultimately transferred 9.320314393658547376 WETH to the attacker EOA after repaying the 18 WETH flash loan plus the 0.009 WETH fee. This directly matches the report's stated success predicate.

5. Adversary Flow Analysis

The attacker cluster contains three critical addresses. The EOA 0x0195448a9c4adeaf27002c6051c949f3c3234bb5 sent both adversary-crafted transactions and received the final WETH profit transfer. Contract 0x98c2e1e85f8bf737d9c1450dd26d4a4bf880b892 executed the flash loan, EHIVE purchases, helper orchestration, and liquidation. Contract 0xe7d9a93541fa79d6ecf3dc5997632177146dcb84 served as the helper factory/controller.

The adversary lifecycle has two distinct phases:

  1. Priming in tx 0xd9156f507c701a09d3312e1987383c7c882df50b3127e1adfd74d74052642114 at block 17690498.
  2. Capital acquisition, inflation, and liquidation in tx 0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c1 at block 17961696.

The first phase established the stale timestamps. The second phase borrowed WETH, bought EHIVE, moved the balance through the helper chain to repeatedly realize retroactive rewards, then sold the inflated EHIVE back into the live EHIVE/WETH pair. No privileged access, private orderflow, or attacker-specific on-chain artifacts were required beyond contracts that any user could deploy.

The exploit conditions listed in root_cause.json are also supported by the evidence: staking was enabled, validator 0 existed, the attacker could create old staking addresses, public staking entrypoints allowed the top-up and unstake loop, and a live WETH pair existed to monetize the inflation. All of those conditions were satisfied on-chain at the time of execution.

6. Impact & Losses

The impact has two parts. First, EHIVE's supply accounting was broken because the staking system minted rewards that were not justified by elapsed time on the newly added capital. Second, the attacker converted that inflation into external value by draining WETH from the EHIVE/WETH pair.

The root cause artifact records the measurable pool loss as:

[
  {
    "token_symbol": "WETH",
    "amount": "27329314393658547376",
    "decimal": 18
  }
]

That is 27.329314393658547376 WETH in smallest-unit form, matching the WETH amount paid out by the pair during the final swap. The attacker cluster's net profit after gas was lower because the flash loan had to be repaid and the attacker EOA paid execution gas, but the pool depletion is the protocol-side loss metric.

7. References

  1. EHIVE verified source at 0x4ae2cd1f5b8806a973953b76f9ce6d5fab9cdcfd, especially stake, _userEarned, and unstake.
  2. Priming transaction 0xd9156f507c701a09d3312e1987383c7c882df50b3127e1adfd74d74052642114, including the trace that shows repeated EHIVE::stake(0, 0) helper registration.
  3. Profit transaction 0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c1, including the execution trace that shows repeated helper stake/unstake loops, the Uniswap V2 sale, and the final WETH transfer to the attacker EOA.
  4. Balance diff for tx 0xad818ec910def08c70ac519ab0fffa084b4178014a91cd8aa2f882d972a511c1, which confirms pool WETH depletion, EHIVE inflation, and attacker-cluster profit realization.