TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: low
Invalid

Lack of checks in TempleGold::constructor allows to distribute all TLGD to only one address

Summary

Lack of checks in TempleGold::constructor allows to distribute all TLGD to only one address because it allows to use the same address in initArgs.staking , initArgs.escrow and initArgs.gnosis from initArgs constructor parameter.

Vulnerability Details

This lack of check allows setting the same address to this 3 initArgs fields: _initArgs.staking , initArgs.escrow and _initArgs.gnosis, leading to 100% of minted TLGD be distributed to only one address.
The flaw is present in TempleGold::constructor because it blindly trust initArgs's parameter values:

constructor(
InitArgs memory _initArgs
) OFT(_initArgs.name, _initArgs.symbol, _initArgs.layerZeroEndpoint, _initArgs.executor) Ownable(_initArgs.executor){
staking = ITempleGoldStaking(_initArgs.staking);
escrow = IDaiGoldAuction(_initArgs.escrow); //<@- No validation
teamGnosis = _initArgs.gnosis; //<@- No validation
_mintChainId = _initArgs.mintChainId; //<@- No validation

So if the same address is used all minted TLGD will be distributed only to the defined address
The following PoC shows how using only one address will distribute the 100% minted TGLD, and how the lacks of checks in TempleGold contract allows it:

function test_all_tgld_to_one_address_initArgs() public {
arbitrumOneForkId = fork("arbitrum_one");
address sameAddress = makeAddr("sameaddress");
// NEW
ITempleGold.InitArgs memory initArgs;
initArgs.executor = executor;
initArgs.staking = sameAddress;
initArgs.escrow = sameAddress;
initArgs.gnosis = sameAddress;
initArgs.layerZeroEndpoint = layerZeroEndpointArbitrumOne;
initArgs.mintChainId = arbitrumOneChainId;
initArgs.name = TEMPLE_GOLD_NAME;
initArgs.symbol = TEMPLE_GOLD_SYMBOL;
// AFTER
templeGold = new TempleGold(initArgs);
templeToken = new FakeERC20("Temple Token", "TEMPLE", executor, 1000 ether);
staking = new TempleGoldStaking(rescuer, executor, address(templeToken), address(templeGold));
daiGoldAuction = new DaiGoldAuction(
address(templeGold),
daiToken,
treasury,
rescuer,
executor
);
vm.startPrank(executor);
templeGold.setEscrow(address(daiGoldAuction));
_configureTempleGold();
// Here the test starts
console.log("[i] test_nontransferrable_tgld");
vm.startPrank(executor);
vm.warp(block.timestamp + 20 days);
templeGold.mint();
address teamGnosis = templeGold.teamGnosis();
vm.startPrank(teamGnosis);
uint256 balance = templeGold.balanceOf(teamGnosis);
console.log("TeamGnosis Balance => ",balance);
}

To run import console.sol library in TempleGold.t.sol

import "forge-std/console.sol";

And copy the following as a new test case in test/forge/templegold/TempleGold.t.sol
run with verbose mode

forge test -vv --mt test_all_tgld_to_one_address_initArgs

Observe all the minted tokens are distributed to only one address

Impact

High cause if an EOA is used, will allow to get all minted TGLD.
However attack complexity is High.

Tools Used

Manual Review

Recommendations

Implement a check to at least ensure _initArgs.staking and initArgs.escrow are different:

constructor(
InitArgs memory _initArgs
) OFT(_initArgs.name, _initArgs.symbol, _initArgs.layerZeroEndpoint, _initArgs.executor) Ownable(_initArgs.executor){
if (_initArgs.staking == _initArgs.escrow) { revert CommonEventsAndErrors.InvalidAddress(); } //<@= here
staking = ITempleGoldStaking(_initArgs.staking);
escrow = IDaiGoldAuction(_initArgs.escrow);
teamGnosis = _initArgs.gnosis;
_mintChainId = _initArgs.mintChainId;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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