Reproduced Exploit

IntentX: minting xINTX updates reward token id 0 and the new stake takes 1,000

May 2024•Other•logic•2 min read

Chain

Other

Category

logic

Date

May 2024

Source

AuditVault

EVM Playground

Source-level debugger — step opcodes and Solidity in sync

evm-hack-analyzer

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.

Loading fork state…

Source & credit. Reproduction of a public audit finding curated by AuditVault — the original finding: 59428-incorrect-reward-updates-upon-xintx-minting-quantstamp-inten. Standalone Foundry PoC and full write-up: 59428-incorrect-reward-updates-upon-xintx-minting-quantstamp-inten_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/logic/reward-calculation

_stake declares uint256 _tokenId and calls _updateReward(_tokenId) before assigning it, so the update runs on token id 0. The new xINTX position keeps rewardDebt of 0. An early staker deposits 100 INTX. 1,000 reward tokens are then notified. A later mint of another 100 INTX claims that entire 1,000 because its debt was never set to the accumulator.

SOLIDITY
function _updateReward(uint256 tokenId) internal {
    updates += 1; // @> VULN: tokenId is 0 on mint
    rewardDebt[tokenId] = (staked[tokenId] * accRewardPerToken) / 1e18;
}

Diagrams#

flowchart TD A["Early staker mints xINTX for 100 INTX"] --> B["Reward update runs on token id 0"] B --> C["1,000 reward tokens are notified against that stake"] C --> D["Attacker mints a second xINTX"] D --> E["The new id still has reward debt 0"] E --> F["Claim pays the attacker the full 1,000"]

Impact#

The later minter receives 1,000 reward tokens. The staking contract's reward balance is 0, so the early staker cannot be paid. The fixed mint sets rewardDebt to the current accumulator after the stake is recorded. The later mint then claims 0 and the early staker claims the 1,000.

PoC#

BASH
cd 59428-incorrect-reward-updates-upon-xintx-minting-quantstamp-inten_exp
forge test -vv

Sources & further analysis#

Reproductions & code

Alerts & third-party analyses

  • Web3Sec X hacked database: search.
  • Rekt leaderboard: search.
  • Solodit incident search: search.

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.