Proper Cider Shark
High
Summary Missing Input Validation for Critical Addresses in PoolFactory
Root Cause In PoolFactory.sol:initialize there are missing validation checks for critical addresses (_governance, _deployer, _oracleFeeds, and beacon implementations) which could allow zero addresses to be set during initialization. In [PoolFactory.sol:L141-159]https://github.com/sherlock-audit/2024-12-plaza-finance/blob/main/plaza-evm/src/PoolFactory.sol#L92-L115) the initialize function lacks validation checks for critical addresses: solidityCopyfunction initialize( address _governance, address _deployer, address _oracleFeeds, address _poolImplementation, address _bondImplementation, address _leverageImplementation, address _distributorImplementation ) initializer public { __UUPSUpgradeable_init(); __Pausable_init();
deployer = Deployer(_deployer); // @audit no validation
governance = _governance; // @audit no validation
oracleFeeds = _oracleFeeds; // @audit no validation
_grantRole(GOV_ROLE, _governance);
// Stores beacon implementation addresses
poolBeacon = _poolImplementation; // @audit no validation
bondBeacon = _bondImplementation; // @audit no validation
leverageBeacon = _leverageImplementation; // @audit no validation
distributorBeacon = _distributorImplementation; // @audit no validation
}
Internal Pre-conditions Contract must be in uninitialized state before initialization Deployer needs access to call initialize() function
External Pre-conditions The protocol becomes permanently broken and unusable. Specific impacts include:
If governance is address(0): Contract becomes ungovernable, no role management or upgrades possible If deployer is address(0): Pool creation functionality breaks If oracleFeeds is address(0): Price feed functionality fails If any beacon is address(0): New pool creation fails
Recovery would require complete redeployment of the system and migration of all user funds.
Attack Path Deployer calls initialize() with address(0) for one or more critical parameters: solidityCopypoolFactory.initialize( address(0), // governance deployerAddress, oracleFeeds, poolBeacon, bondBeacon, leverageBeacon, distributorBeacon );
Contract becomes initialized with zero address(es) for critical components Core functionality becomes permanently broken due to invalid addresses
Impact The protocol becomes permanently broken and unusable. Specific impacts include:
If governance is address(0): Contract becomes ungovernable, no role management or upgrades possible If deployer is address(0): Pool creation functionality breaks If oracleFeeds is address(0): Price feed functionality fails If any beacon is address(0): New pool creation fails
Recovery would require complete redeployment of the system and migration of all user funds.
PoC // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.26;
import "forge-std/Test.sol"; import {PoolFactory} from "../src/PoolFactory.sol"; import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; import {Pool} from "../src/Pool.sol"; import {BondToken} from "../src/BondToken.sol"; import {LeverageToken} from "../src/LeverageToken.sol"; import {Distributor} from "../src/Distributor.sol"; import {Deployer} from "../src/utils/Deployer.sol";
contract PoolFactoryInitializeTest is Test { PoolFactory private poolFactory; address private governance = address(0x3); address private deployerAddress = address(0x1); address private oracleFeeds = address(0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70);
function setUp() public { // Deploy the PoolFactory contract poolFactory = new PoolFactory(); }
function testInitializeWithZeroAddresses() public { // Deploy implementations for beacons address poolImplementation = address(new Pool()); address bondImplementation = address(new BondToken()); address leverageImplementation = address(new LeverageToken()); address distributorImplementation = address(new Distributor());
// Deploy beacons
address poolBeacon = address(new UpgradeableBeacon(poolImplementation, governance));
address bondBeacon = address(new UpgradeableBeacon(bondImplementation, governance));
address leverageBeacon = address(new UpgradeableBeacon(leverageImplementation, governance));
address distributorBeacon = address(new UpgradeableBeacon(distributorImplementation, governance));
// Test zero address for governance
vm.expectRevert("Invalid governance address");
poolFactory.initialize(
address(0), // Zero address for governance
deployerAddress,
oracleFeeds,
poolBeacon,
bondBeacon,
leverageBeacon,
distributorBeacon
);
// Test zero address for deployer
vm.expectRevert("Invalid deployer address");
poolFactory.initialize(
governance,
address(0), // Zero address for deployer
oracleFeeds,
poolBeacon,
bondBeacon,
leverageBeacon,
distributorBeacon
);
// Test zero address for oracleFeeds
vm.expectRevert("Invalid oracle feeds address");
poolFactory.initialize(
governance,
deployerAddress,
address(0), // Zero address for oracleFeeds
poolBeacon,
bondBeacon,
leverageBeacon,
distributorBeacon
);
// Test zero address for poolBeacon
vm.expectRevert("Invalid pool implementation address");
poolFactory.initialize(
governance,
deployerAddress,
oracleFeeds,
address(0), // Zero address for poolBeacon
bondBeacon,
leverageBeacon,
distributorBeacon
);
// Test zero address for bondBeacon
vm.expectRevert("Invalid bond implementation address");
poolFactory.initialize(
governance,
deployerAddress,
oracleFeeds,
poolBeacon,
address(0), // Zero address for bondBeacon
leverageBeacon,
distributorBeacon
);
// Test zero address for leverageBeacon
vm.expectRevert("Invalid leverage implementation address");
poolFactory.initialize(
governance,
deployerAddress,
oracleFeeds,
poolBeacon,
bondBeacon,
address(0), // Zero address for leverageBeacon
distributorBeacon
);
// Test zero address for distributorBeacon
vm.expectRevert("Invalid distributor implementation address");
poolFactory.initialize(
governance,
deployerAddress,
oracleFeeds,
poolBeacon,
bondBeacon,
leverageBeacon,
address(0) // Zero address for distributorBeacon
);
} }