Skip to content

Conversation

@tamtamchik
Copy link
Member

@tamtamchik tamtamchik commented Nov 5, 2025

Description

Fix doppelgänger pubkeys acceptance for TV calculations.

Initial State

Vault1: 1 ETH balance
Vault2: 32 ETH balance

Attack Sequence

Step 1: External Predeposit to validator1

Predeposit validator1 using external ETH (not from PDG)
Validator1 configured with vault1's withdrawal credentials (WC1)
Status: Pending validator
vault1 totalValue: 1 ETH (unchanged, since PDG state = None)

Step 2: PDG Predeposit to Same Validator

Use PDG to predeposit to validator1 again
This time with vault2's withdrawal credentials (WC2)
Deposit: 1 ETH from vault2, stage remaining 31 ETH
vault2 totalValue: 31 ETH (32 - 1 = 31, since validator doesn't point to vault2 yet)

Step 3: The Exploit

vault1 totalValue becomes 2 ETH!
Why?

vault1 still has 1 ETH in balance
validator1 now has PDG state = PREDEPOSITED (with WC2)
BUT: System incorrectly attributes the predeposited validator to vault1 because it was originally associated with WC1
vault1 gains +1 ETH credit for the predeposited validator

Step 4: Borrow and Compensate Race

vault1 borrows against the inflated 2 ETH totalValue
System then compensates vault2 for the staged ETH
vault2 totalValue: Returns to 32 ETH
vault1 totalValue: Drops back to 1 ETH (but debt already issued)
Result: Bad debt created

Step 5: Parallel Exploitation

Repeat steps 1-4 multiple times in parallel to amplify bad debt creation.

Root Cause

The system fails to properly handle validator credential switches, allowing double-counting of validator value across vaults during the window between predeposit and compensation.

Related Issue/Task

How Has This Been Tested?

Describe how you tested the changes:

  • Local tests (e.g., pytest)
  • Manual testing (describe steps)
  • Not tested (explain why)

Checklist

  • Documentation updated (if required)
  • New tests added (if applicable)
  • CSM_STATE_VERSION is bumped (if the new version affects data in the cache)

@tamtamchik tamtamchik requested a review from a team as a code owner November 5, 2025 17:46
TheDZhon
TheDZhon previously approved these changes Nov 5, 2025
Copy link

@TheDZhon TheDZhon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, though have a question

}

# --- Web3 Mock ---
w3_mock = MagicMock()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a better mock, that can be used instead, in conftest.py

@F4ever
Copy link
Member

F4ever commented Nov 7, 2025

One integration test fails - expected. Will be fixed after protocol upgrade

@F4ever F4ever merged commit d6c09a1 into develop Nov 7, 2025
10 of 11 checks passed
@F4ever F4ever deleted the feat/fix-state branch November 7, 2025 10:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants