Reproduced Exploit

Audius claimRewards pays the delegator 550 instead of 50

The service provider has 1000 locked in a pending decrease, 1000 unlocked, and 1000 delegated. processClaim mints 100. totalRewards is computed as staking balance minus outside balance: 3100 - 2000 = 1100, which is the locked 1000 plus the minted 100. The delegator is credited 1000 * 1100 / 2000 =…

Aug 2020•Other•logic•3 min read

Chain

Other

Category

logic

Date

Aug 2020

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: 11316-h05-rewards-calculation-is-incorrect-when-the-service-provid. Standalone Foundry PoC and full write-up: 11316-h05-rewards-calculation-is-incorrect-when-the-service-provid_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/logic/reward-calculation

Key info#

ProtocolAudius
FindingOpenZeppelin H05, AuditVault 11316
Vulnerable codeDelegateManager.claimRewards
HarmDelegator is paid 550 AUDIO; the fair share of the minted rewards is 50
Chainlocal synthetic

TL;DR#

The service provider has 1000 locked in a pending decrease, 1000 unlocked, and 1000 delegated. processClaim mints 100. totalRewards is computed as staking balance minus outside balance: 3100 - 2000 = 1100, which is the locked 1000 plus the minted 100. The delegator is credited 1000 * 1100 / 2000 = 550. Using the minted 100, the same formula pays 50. The control sets totalRewards to the minted amount and pays 50.

The vulnerable code#

SOLIDITY
_processClaim();
uint256 _totalBalanceInStaking = token.balanceOf(address(this));
uint256 _totalBalanceInSPFactory = UNLOCKED.add(spLockedStake);
_totalBalanceInSPFactory = _totalBalanceInSPFactory.sub(spLockedStake);
uint256 _totalBalanceOutsideStaking = _totalBalanceInSPFactory.add(DELEGATED);
// ...
uint256 _totalRewards = totalBalanceInStaking.sub(totalBalanceOutsideStaking);
// @> VULN: totalRewards is locked stake plus minted rewards, not the minted rewards alone
totalRewards = _totalRewards;

_totalRewards is the audited subtraction. viaIR maps the store on the next line, which is what the playground highlights.

Root cause#

The pending decrease is subtracted from the service-provider factory balance and therefore from the "outside" total, but it is still inside the staking balance. Subtracting outside from staking adds the locked stake back in and calls it rewards.

Preconditions#

A decrease-stake request of 1000 is pending. Delegated stake is 1000, unlocked service-provider stake is 1000, and the round mints 100 of rewards. The delegator is paid from that inflated total.

Attack walkthrough#

  1. processClaim mints 100. Staking balance is 3100.
  2. Outside balance is unlocked 1000 plus delegated 1000 = 2000. The locked 1000 was subtracted.
  3. totalRewards is stored as 1100.
  4. Delegator credit is 1000 * 1100 / 2000 = 550. Fair credit is 50.
  5. 550 AUDIO is transferred to the delegator.

Diagrams#

flowchart TD A["Pending decrease of 1000"] --> B["processClaim mints 100"] B --> C["VULN: totalRewards = 3100 - 2000 = 1100"] C --> D["Delegator credit is 550"] D --> E["Fair credit is 50"] E --> F["Delegator is paid 550"]

Impact#

The delegator is paid 550 AUDIO against a fair 50. totalRewards is 1100 against 100 minted. The extra 450 is principal. The control pays 50.

Audius later reported a second skew in the service-provider base that can cancel the aggregate recorded stake. This reduction isolates the totalRewards formula the report blames and shows the delegator payment that formula produces.

Remediation#

Set totalRewards to the amount processClaim minted, and do not reconstruct it from the difference of two balances that treat locked stake differently.

How to reproduce#

BASH
cd 11316-h05-rewards-calculation-is-incorrect-when-the-service-provid_exp
forge test -vv

Sources#


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.