DEV Community

Daniel
Daniel

Posted on • Edited on

How Stale GLV Share Pricing Allowed New Depositors to Capture Pending Insurance Recapitalization

Disclosure summary

During the 0xMarkets audit contest, I found a share pricing flaw in the GLV market token deposit path.

A depositor could enter a GLV while another supported market had a pending insurance recapitalization that was not yet reflected in the vault valuation. Because the protocol minted the new shares against that incomplete value, the depositor received more ownership than the deposit justified.

Once the insurance injection was settled, part of the recapitalization accrued to the new depositor. Existing GLV holders suffered the matching loss through permanent dilution.

Triage confirmed the underlying value transfer and grouped my report with an already accepted insurance recapture finding that reached the same valuation flaw through the underlying market deposit path. The grouped issue was classified as High, and my share of the reward was $343.64.

I argued that the confirmed impact met the published Critical category for direct theft of user funds. Triage maintained High after several detailed appeals.

This article focuses first on the technical behavior, which was no longer disputed, and then explains the severity disagreement separately.

How GLV share pricing should work

A GLV can hold exposure to several supported GM markets. Its holders own a proportional claim on the economic value represented by all of those markets.

When a new user deposits value, the number of shares minted should depend on two things:

  1. The value being added by the depositor

  2. The complete value already owned by the existing holders

Consider a GLV that supports Market A and Market B.

The attacker deposits GM tokens from Market A.

Market B has already suffered enough drawdown to qualify for an insurance injection. The reserve exists, a valid epoch snapshot exists, and the configured drawdown threshold has been crossed. The recapitalization is pending only because the protocol action that performs the transfer has not yet occurred.

Economically, that pending value belongs to the holders who owned the GLV exposure when the loss occurred. Triage explicitly agreed with this point.

A simplified share mint calculation looks like this:

minted shares = deposit value multiplied by current supply divided by GLV value
Enter fullscreen mode Exit fullscreen mode

Let:

  1. V represent the GLV value before the pending insurance injection

  2. I represent the pending insurance injection

  3. D represent the attacker deposit value

The vulnerable flow prices the deposit using V.

The economically complete denominator is V plus I.

When I is omitted, the denominator becomes smaller than it should be. The same deposit therefore receives more GLV shares.

That is the economic core of the vulnerability.

The broken invariant

The invariant is straightforward:

New shares must never be minted against a vault valuation that excludes value already economically owed to existing holders.

The public entry point is GlvRouter.createGlvDeposit.

A user can deposit existing GM tokens by setting isMarketTokenDeposit to true.

A keeper later executes the request through GlvHandler.executeGlvDeposit, which reaches GlvDepositUtils.executeGlvDeposit.

The relevant execution order can be reduced to this:

receivedMarketTokens = processMarketDeposit();

glvValue = GlvUtils.getGlvValue(
    dataStore,
    oracle,
    glv,
    true
);

glvSupply = GlvToken(glv).totalSupply();

mintAmount = getMintAmount(
    receivedMarketTokens,
    glvValue,
    glvSupply
);
Enter fullscreen mode Exit fullscreen mode

The protocol processes the incoming market tokens and then reads the GLV value before minting the new shares.

The problem is not the order between the incoming deposit and the valuation. The problem is that GlvUtils.getGlvValue values every supported market without first settling or accounting for pending insurance injections.

This creates a state ordering gap:

  1. Existing holders bear the market loss

  2. Insurance recapitalization becomes economically owed to them

  3. The recapitalization remains pending and absent from the current GLV value

  4. A new depositor mints shares against the depressed value

  5. The insurance value enters after those new shares exist

  6. The new depositor captures part of the recapitalization

  7. Existing holders retain a smaller ownership percentage and lose the matching value

Why the GLV market token branch mattered

My report did not use the standard internal market deposit branch.

When isMarketTokenDeposit is true, the protocol accepts existing GM tokens, transfers them into the GLV, and returns the received amount. The relevant branch appears in GlvDepositUtils.

This attacker path does not create a normal internal Deposit and does not call ExecuteDepositUtils.

The proof verified that:

  1. The attacker used the public GLV deposit entry point

  2. isMarketTokenDeposit was true

  3. The initial long token was zero

  4. The initial short token was zero

  5. Both swap paths were empty

  6. The normal Deposit count did not change during execution

  7. ExecuteDepositUtils was not used by the attacker path

This established that the GLV wrapper exposed a distinct route to the same underlying flaw.

Triage grouped it with an accepted finding in the market deposit path because both routes eventually priced newly minted shares against a depressed valuation while the same pending insurance value remained unsettled.

I accepted the grouping for the purpose of the discussion. The path distinction still matters for reachability and remediation because fixing only one entry route can leave another wrapper route exposed to the same state mismatch.

Complete exploitation sequence

Existing holder state

Existing users already hold GLV shares.

The GLV owns GM exposure from Market A and Market B.

Market B has an insurance reserve and a valid epoch snapshot. Its drawdown exceeds the configured trigger, so an insurance injection is pending.

Attacker preparation

The attacker obtains Market A GM through the real protocol deposit flow.

The exploit does not require direct GM minting, governance control, an administrator, a compromised keeper, oracle manipulation, or direct storage modification.

The attacker transfers Market A GM to the GLV vault and creates a public GLV deposit request with isMarketTokenDeposit enabled.

Excess share minting

A keeper executes the request while the Market B injection is still pending.

The protocol calculates the GLV mint denominator without including the pending recapitalization.

The attacker receives more GLV shares than the deposited Market A GM economically justifies.

At that moment, the attacker owns an excess claim on the vault and the earlier holders have been diluted.

Insurance settlement

After the GLV deposit has executed, the attacker can initiate a MarketDecrease from a position under their control.

That production action reaches InsuranceFundUtils.attemptInjectPool through the real decrease flow in DecreasePositionCollateralUtils.

The reserve enters Market B after the attacker already owns the excess GLV shares.

The attacker captures part of the injected value. Existing holders receive less than they would have received if the recapitalization had been included before the share mint.

The asynchronous execution nuance

The exploit is not completed in one atomic transaction.

GLV deposits use an asynchronous request architecture. The user submits a request, and a keeper executes it later.

A competing MarketDecrease, liquidation, or ADL action could settle the pending injection before the attacker’s deposit is executed. The attacker cannot guarantee the order of every event inside that window.

That uncertainty should be described precisely, however.

If the keeper executes the GLV request while the injection is still pending, the excess mint occurs deterministically. After that point, the attacker can initiate the MarketDecrease that settles the injection and realizes the captured value.

Triage initially stated that the settlement depended entirely on an unrelated event outside the attacker’s control. After reviewing the proof, they corrected that statement and acknowledged that the attacker can initiate the action that settles the injection after the deposit.

Their remaining position was that the race before deposit execution reduced reliability and supported High severity.

My position was that asynchronous execution affects likelihood, but it does not change the successful impact. Once the vulnerable deposit executes in the pending state, the ownership transfer follows deterministically.

How the proof was built

The proof used the real 0xMarkets deployment fixture and the actual protocol contract implementations.

It recreated the complete lifecycle instead of stopping at a mathematical discrepancy.

The test established that:

  1. Existing GLV holders were present before the attacker

  2. The GLV supported two distinct markets

  3. Market B exposure already belonged to the GLV

  4. Market B had an insurance reserve

  5. Market B had a valid epoch snapshot

  6. Market B drawdown exceeded the insurance trigger

  7. The injection was pending before the attacker entered

  8. The attacker obtained Market A GM through the real deposit flow

  9. The attacker used the GLV market token deposit branch

  10. No normal internal Deposit was created during the exploit action

  11. The insurance injection remained pending after the attacker received GLV shares

  12. A real MarketDecrease settled the injection after the attacker entered

  13. The attacker received positive excess value

  14. Existing holders suffered the exact matching loss

The proof did not depend on a mock GLV, reader, or oracle. It also did not rely on the attacker directly minting MarketToken or direct economic DataStore modification.

Administrative permissions were used only to configure the local test environment. The attacker action itself used the public protocol flow.

The complete test passed in approximately ten minutes.

Measured economic result

The deterministic proof produced these values in protocol precision:

Attacker GM input amount
2000000000000000000000

Actual GLV shares minted
2089737593887520918674

Safe GLV shares
2089737593887520918457

Excess GLV shares
217

Attacker excess value
156164176354695

Existing holder loss
156164176354695
Enter fullscreen mode Exit fullscreen mode

The most important result is the exact equality between the attacker’s excess value and the loss to existing holders.

This was not a discrepancy limited to a view, and the later insurance settlement did not reverse it. The incorrect denominator changed the share supply. The settlement only made the transferred value measurable.

The proof intentionally used conservative local values so the scenario would execute deterministically. Those values were never presented as the protocol maximum.

Maximum capture

The value captured from existing holders can be represented as:

captured value = (D × I) ÷ (V + D)
Enter fullscreen mode Exit fullscreen mode

The formula shows that:

  1. If D equals V, the attacker captures approximately half of I

  2. As D becomes large relative to V, the captured value approaches I

  3. The theoretical ceiling is the full pending insurance injection

This formula became the center of the severity dispute.

Triage argued that I is a recapitalization amount capped by the available reserve rather than capital deposited in the vault or the complete market pool. In their assessment, even capturing all of I remained within the High tier.

I argued that the formula identifies which asset is available for capture, but it does not prove that the asset is economically modest. No absolute limit enforced by the protocol, percentage limit, maximum supported injection, or published monetary threshold separating High from Critical was identified during the appeal.

Both sides agreed on the formula. The disagreement was how its maximum credible result should map to severity.

Capital, fees, and market exposure

Triage also argued that capturing a large part of I requires D to be large relative to V.

A larger deposit means more capital committed to the GLV position, more exposure to the underlying markets, and more potential cost from fees and price impact.

Those factors can reduce practical net profit.

My response was that the deposited GM is exchanged for redeemable GLV shares. The capital is not burned or forfeited. The attacker keeps an asset position and receives excess ownership because of the stale denominator.

I requested a quantitative feasibility analysis using the actual fee parameters, the maximum realizable injection, the capital required, market exposure, price impact, and resulting net profit. Triage did not provide numerical calculations and treated these factors qualitatively.

Why this was more than an accounting error

The protocol did not merely display the wrong value.

It issued the wrong number of ownership shares.

The attacker received a larger claim than the deposit justified. Existing holders retained a smaller claim than they should have kept.

The later insurance injection did not correct the supply, restore the previous ownership percentages, or remove the attacker’s excess shares.

A vault can remain solvent while its holders still lose value. Solvency and ownership correctness are different security properties.

This finding demonstrated measurable dilution with a matching attacker gain and victim loss.

The severity disagreement

By the end of the discussion, the technical behavior itself was no longer disputed.

Triage agreed that:

  1. The depositor was unprivileged

  2. Existing holders suffered a real loss

  3. The loss was not reversed by later settlement

  4. The depositor received the corresponding value

  5. Assets remaining inside the vault did not remove the issue from the theft and value appropriation family

  6. The protocol needed to settle or account for pending insurance before pricing new shares

The disagreement concerned whether that confirmed behavior belonged in High or Critical.

Why triage kept High

Triage relied mainly on three factors.

First, the maximum capture was the pending insurance injection rather than all capital deposited in the GLV or the complete market pool.

Second, the attacker’s deposit was asynchronous and could be preempted by another action that settled the injection first.

Third, capturing a material fraction required significant capital, market exposure, fees, and possible price impact.

Triage also stated that the GLV route inherited the confirmed High severity of the accepted primary route because both were treated as one grouped finding.

For the token issuance category, they distinguished this case from completely unbacked minting. The attacker did make a real GM deposit. The defect was that the protocol calculated too many shares from a stale denominator.

Why I argued Critical

I argued that the confirmed behavior was direct appropriation of value economically owned by identifiable users.

The attacker received an excess ownership claim, and existing holders suffered an equal and permanent loss.

The pending insurance injection was not unclaimed yield. It was a recapitalization triggered by a realized drawdown and economically attributable to the current holders.

I also argued that the published Critical category for direct theft did not expressly require the exploit to be atomic, unbounded, free of attacker capital, or capable of taking the entire pool.

The appeal asked for concrete limits and thresholds, including the maximum possible I, the percentage of holder value that could be transferred, the likelihood threshold applied to asynchronous execution, and the numerical effect of capital and fees.

Those quantitative boundaries were not provided.

I also requested that the grouped finding be assessed independently rather than treating the previous High classification as proof that High was correct.

The final triage response was:

Decision will not be changed.

The official result therefore remained High.

Remediation

The protocol must not price new GM or GLV shares while pending insurance value owed to existing holders is absent from the denominator.

A safe execution sequence is:

  1. Check whether the GLV already has existing supply

  2. Load every supported market

  3. Skip markets with zero GLV balance because they do not represent current holder value

  4. Evaluate pending insurance injections using current oracle prices

  5. Reuse InsuranceFundUtils.attemptInjectPool for the relevant market tokens

  6. Process the incoming GM deposit

  7. Calculate the complete GLV value

  8. Mint the new GLV shares

The first deposit can skip this settlement loop because no existing holder can be diluted.

The same invariant must be enforced across every route that can mint GM or GLV shares. Fixing only the first reported route can leave a wrapper path exposed to the same economic mismatch.

Broader audit lessons

This finding illustrates a pattern that appears far beyond GLV vaults.

Economic ownership can exist before physical settlement.

A protocol may separate loss recognition, insurance entitlement, insurance transfer, vault valuation, and share issuance into different actions.

If a new share mint can occur between entitlement and settlement, a depositor may capture value generated by losses borne by earlier holders.

When reviewing vaults, wrappers, and liquidity tokens, I now ask:

  1. Does any pending action increase or restore vault value?

  2. Who economically owns that pending value?

  3. Can users mint or redeem shares before settlement?

  4. Do direct and wrapper deposit routes use the same synchronized valuation?

  5. Can a user enter through one supported market and capture value from another?

  6. Does later settlement correct ownership, or does it only reveal the dilution?

  7. Can a workflow that depends on keepers create an exploitable ordering window?

  8. Is impact being evaluated from the maximum credible state rather than only the conservative proof parameters?

These questions are useful because every individual function can appear correct while the combined lifecycle still transfers value incorrectly.

Conclusion

The 0xMarkets GLV market token deposit path allowed a new depositor to mint shares against a valuation that excluded pending insurance recapitalization for another supported market.

The attacker could enter with Market A GM while Market B had a pending injection. The stale denominator created excess GLV shares. A later production MarketDecrease settled the insurance injection, and those excess shares gave the attacker value that economically belonged to the existing holders.

The proof demonstrated a complete and measurable transfer:

  1. Positive attacker excess value

  2. Equal existing holder loss

  3. Permanent dilution

  4. Public attacker access

  5. No mock dependency

  6. A real insurance settlement after the deposit

Triage confirmed the value transfer but classified the grouped finding as High because the capture was limited to the pending injection, execution was asynchronous, and material capture required capital and exposure.

I maintained that the permanent appropriation of value owned by users met the published Critical category for direct theft and that the quantitative basis for the downgrade was not established.

The official result remained High, and my reward was $343.64.

Regardless of that classification dispute, the engineering lesson is clear:

A protocol must never issue new vault shares using a denominator that excludes value already economically owed to existing holders.

Top comments (0)