Reproduced Exploit

Ostium scaleVariables settles PnL at 20 instead of 10

scaleVariables scales accPnlPerToken only when it is negative. A vault with 100 tokens, 100 shares and trader profit of 10 has accPnlPerToken of 0.1. A 90-token deposit mints 100 shares and leaves the accumulator at 0.1. Implied PnL becomes 200 * 0.1 = 20 instead of 10. Settlement pays the trader 2…

Sep 2025•Other•arithmetic•3 min read

Chain

Other

Category

arithmetic

Date

Sep 2025

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: 65202-h-04-code-does-not-scale-accpnlpertoken-in-scalevariables-al. Standalone Foundry PoC and full write-up: 65202-h-04-code-does-not-scale-accpnlpertoken-in-scalevariables-al_exp in the evm-hack-registry mirror.


Vulnerability classes: vuln/arithmetic/decimal-mismatch · vuln/logic/price-calculation

Key info#

ProtocolOstium
FindingPashov H-04, AuditVault 65202
Vulnerable codeVault.scaleVariables
HarmSettlement pays 20 tokens; the fair PnL is 10; off by 10
Chainlocal synthetic

TL;DR#

scaleVariables scales accPnlPerToken only when it is negative. A vault with 100 tokens, 100 shares and trader profit of 10 has accPnlPerToken of 0.1. A 90-token deposit mints 100 shares and leaves the accumulator at 0.1. Implied PnL becomes 200 * 0.1 = 20 instead of 10. Settlement pays the trader 20. Scaling the positive accumulator pays 10.

The vulnerable code#

SOLIDITY
uint256 supply = totalSupply();
// @> VULN: a positive accPnlPerToken is left unchanged, so implied PnL grows with the new shares
if (accPnlPerToken < 0) {
    accPnlPerToken = accPnlPerToken * supply.toInt256()
        / (isDeposit ? (supply + shares).toInt256() : (supply - shares).toInt256());
}

The control applies that same ratio when the accumulator is positive: 0.1e18 * 100 / 200 = 0.05e18, and 0.05 * 200 = 10.

Root cause#

The sign check treats a positive per-token PnL as "already correct". It is correct only for the old supply. New shares inherit the old per-token value, so the implied total doubles when the share supply doubles.

Preconditions#

accPnlPerToken is positive. A deposit increases the share supply. The numbers are the report's example, scaled by 1e18: 100 tokens, 100 shares, profit 10, deposit 90.

Attack walkthrough#

  1. The depositor adds 90 tokens and receives 100 shares.
  2. scaleVariables sees a positive accumulator and writes nothing.
  3. Supply is 200 and accPnlPerToken is still 0.1e18.
  4. settle pays 20e18 to the trader.
  5. The fair payment is 10e18. The difference is 10e18.

Diagrams#

flowchart TD A["100 tokens, 100 shares, PnL 10"] --> B["Deposit 90 and mint 100 shares"] B --> C["VULN: positive accPnlPerToken is not scaled"] C --> D["Implied PnL becomes 20"] D --> E["Trader is paid 20"] E --> F["Fair settlement is 10, off by 10"]

Impact#

Traders are settled 20 tokens of PnL when the open profit is 10. The extra 10 comes out of depositor equity. The control pays 10.

Remediation#

Scale accPnlPerToken by supply / (supply + shares) on deposits, and by supply / (supply - shares) on withdrawals, for both signs.

How to reproduce#

BASH
cd 65202-h-04-code-does-not-scale-accpnlpertoken-in-scalevariables-al_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.