Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Risk of Proxy Storage Collision

Summary

The MarketMakingEngine contract inherits multiple branches (UpgradeBranch, LookupBranch, CreditDelegationBranch, etc.), which may contain storage variables. Additionally, it extends RootProxy, which also likely manages storage slots. If these contracts do not properly align storage layouts, storage collision can occur, leading to data corruption and unpredictable contract behavior.

Vulnerability Details

Title: Proxy Storage Collision Leading to Data Corruption

  • Affected Contract: MarketMakingEngine.sol

  • Root Cause: Unaligned storage variables across multiple inherited contracts

  • Impact: Potential state corruption, leading to loss of funds or unintended behavior

Root Cause

  1. Solidity uses slot-based storage allocation, meaning contracts that extend multiple parents must align storage layouts.

  2. If RootProxy and the inherited branches (UpgradeBranch, LookupBranch, etc.) introduce new state variables without storage gaps, they can overwrite each other's storage slots.

  3. This can cause critical contract state corruption, leading to malfunctioning logic, loss of funds, or security vulnerabilities.

Impact

  • Corruption of stored variables, which can result in:

    • Loss of governance control

    • Unrecoverable funds if balances are corrupted

    • Malfunctioning upgrade logic in UpgradeBranch

    • Unexpected contract behavior

  • Bricked contracts, if corrupted variables cause a revert loop

  • Unintended access control changes, leading to potential contract takeovers

Tools Used

  • Solidity Storage Layout Checker

  • Hardhat & Foundry (for dynamic simulation)


Proof of Concept (PoC) – Simulating Storage Collision

simulate storage corruption using Hardhat. The test :

  1. Deploy MarketMakingEngine.sol

  2. Attempt to store a variable in a parent contract

  3. Check if another variable gets overwritten due to misalignment

Hardhat Test Script

const { expect } = require("chai");
const { ethers } = require("hardhat");
describe("Proxy Storage Collision Test", function () {
let deployer, attacker, MarketMakingEngine, marketMakingEngine;
before(async () => {
[deployer, attacker] = await ethers.getSigners();
// Deploy MarketMakingEngine contract
const MarketMakingEngineFactory = await ethers.getContractFactory("MarketMakingEngine");
marketMakingEngine = await MarketMakingEngineFactory.deploy(/* initParams */);
await marketMakingEngine.deployed();
});
it("Should detect storage slot collision", async function () {
// Store a variable in a proxy branch (assuming some setter exists)
await marketMakingEngine.setCreditDelegation(100);
// Retrieve the variable from another branch (assuming misalignment)
const corruptedValue = await marketMakingEngine.getVaultRouterConfig();
// If storage slots collide, the value will be incorrect
expect(corruptedValue).to.not.equal(100);
});
});

Mitigation & Recommendations

Short-Term Fix:

Use Storage Gaps

  • Add a storage gap in each inherited contract to prevent slot collisions:

uint256[50] private __gap;

Verify Storage Layout Before Upgrades

  • Use Hardhat’s storageLayout plugin to compare storage across contract versions.

Long-Term Fix:

Use EIP-1967 Proxy Standard

  • Follow EIP-1967 to explicitly separate logic & data storage using reserved storage slots.

  • Ensure RootProxy only stores immutable state and delegates logic to implementations.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.