2021-04-maple-findings's Issues
Test of Maple Finance contest form
Email address
Handle
adamavenir
Eth address
123123
Vulnerability details
1
Impact
2
Proof of concept
3
Tools used
4
Recommended mitigation steps
5
Confirm/Delete a TODO comment on stake lockup period in StakeLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
The below comment on the stake lockup period (L52 in StakeLocker.sol constructor) indicates that the default value has not been confirmed:
lockupPeriod = 180 days; // TODO: Confirm default
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Confirm the correct default value and delete the TODO comment on stake lockup period.
Vulnerable to potential reentrancy attacks in Loan.sol
Handle
0xRajeev
Vulnerability details
Impact
Checks-Effects-Interactions (CEI) pattern not followed in calls to safeTransfer/safeTransferFrom, after which contract state is updated. While liquidityAsset/collateralAsset may be trusted tokens for now, this may become an issue in future if scope is expanded to include user-supplied (i.e. untrusted) ERC20 tokens as assets. In such cases, the safeTransfer/safeTransferFrom implementations may be malicious and cause issues via reentrancy.
Proof of Concept
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Loan.sol#L203
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Loan.sol#L286
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Loan.sol#L318
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Loan.sol#L365
Tools Used
Manual Analysis
Recommended Mitigation Steps
Consider CEI patterns or use ReentrancyGuards from OpenZeppelin.
Missing input validation on function parameter for zero address in StakeLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended especially when they are used in token transfers. Zero-address check is missing on the dst parameter of the pull() function in StakeLocker.sol.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Perform zero address input validation on dst parameter.
Missing event for critical operation of new Funding locker creation in FundingLockerFactory.sol
Handle
0xRajeev
Vulnerability details
Impact
Lockers are critical contracts that hold custody of different Maple assets. While there are five lockers created initially (as described in https://github.com/maple-labs/maple-core/wiki/Lockers), such new lockers created by the factory should be logged as events for off-chain monitoring, similar to whats done in StakeLocker. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log locker creation.
Missing event for critical operation of new Collateral locker creation in CollateralLockerFactory.sol
Handle
0xRajeev
Vulnerability details
Impact
Lockers are critical contracts that hold custody of different Maple assets. While there are five lockers created initially (as described in https://github.com/maple-labs/maple-core/wiki/Lockers), such new lockers created by the factory should be logged as events for off-chain monitoring, similar to whats done in StakeLocker. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log locker creation.
Use of now
Handle
gpersoon
Vulnerability details
Impact
The global variable "now" is used, which is deprecated starting in solidity 7.0:
https://docs.soliditylang.org/en/v0.7.0/070-breaking-changes.html#changes-to-the-syntax
block.timestamp is used in a lot of other locations
Proof of Concept
StakeLocker.sol: newDate = prevDate.add(dTime.mul(amt).div(balanceOf(who) + amt)); // stakeDate + (now - stakeDate) * (amt / (balance + amt))
PoolLib.sol: newDate = prevDate.add(dTime.mul(amt).div(balance + amt)); // prevDate + (now - prevDate) * (amt / (balance + amt))
Tools Used
grep -i now *.sol -S
Recommended Mitigation Steps
Replace now with block.timestamp
Mirrored admin variables in global context, Pool, PoolFactory, Loan and LoanFactory may make it confusing for deployment and maintenance
Handle
0xRajeev
Vulnerability details
Impact
The access control model for the different contracts and how they interact is confusing and may cause issues during deployment and maintenance. Multiple contracts have the notion of admin(s), all of which use setAdmin function to update admin status. This mirroring and reuse of the admin variable is susceptible to accidents.
Proof of Concept
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L20
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Pool.sol#L55
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/PoolFactory.sol#L19
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Loan.sol#L58
https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/LoanFactory.sol#L27
Tools Used
Manual Analysis
Recommended Mitigation Steps
Rename the different admin variables e.g. adminGlobal, adminPool, adminLoan. Document the access control roles, hierarchy and interactions explicitly.
Incorrect Stability Assumption
Handle
0xsomeone
Vulnerability details
Impact
An arbitrage opportunity presents itself whereby a user can exaggerate the discrepancy via flash loans between the USDC price reported and the actual USDC price to f.e. acquire a better rate for their loan. The impacted features of the system can be found here: https://github.com/maple-labs/maple-core/wiki/Oracles
Proof of Concept
The UsdOracle
incorrectly assumes that USDC
has a one-to-one price correlation with USD
. This is false, as evident here: https://data.chain.link/?search=usdc
The discrepancy which fluctuates daily can present arbitrage opportunities that can siphon funds out of the system.
Tools Used
Manual review.
Recommended Mitigation Steps
We advise that the actual Chainlink oracle is utilized to accurately represent what the USDC
rate is to ensure this issue does not occur.
Safemath frequently not used
Handle
gpersoon
Vulnerability details
Impact
On a large number of occasions SafeMath isn't used.
SafeMath is used in other places though, sometimes even in the same expression.
This could lead to overflows/underflows.
Proof of Concept
Some examples:
Pool.sol: poolLosses = poolLosses.add(defaultSuffered - liquidityAssetRecoveredFromBurn);
StakeLocker.sol: newDate = prevDate.add(dTime.mul(amt).div(balanceOf(who) + amt)); // stakeDate + (now - stakeDate) * (amt / (balance + amt))
LoanLib.sol: return collateralRequiredWAD.div(10 ** (18 - collateralAsset.decimals())); // 18 - (18 - collateralDecimals) = collateralDecimals
Tools Used
Search the source files for:
+,-, *, /, ++. --, **
grep " * " *.sol -S
grep " / " *.sol -S
grep " + " *.sol -S
grep " - " *.sol -S
grep -- *.sol -S
- characters are more difficult to find with grep
Recommended Mitigation Steps
Check the code and add SafeMath where appropriate, or use solidity 8.x
Constructor arguments to MapleTreasury not validated
Handle
JMukesh
Vulnerability details
Impact
Its impact can be high since,since there is no checking of address it can be -- - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
Proof of Concept
In MapleTreasury.sol:
address public immutable mpl; // MapleToken contract
address public globals; // MapleGlobals contract
address public immutable uniswapRouter; // Official UniswapV2 router contract
--> for above state variable there is no checking of address in the constructor
Tools Used
No tool is used
Recommended Mitigation Steps
Use openzeppelin - address library
claim doesn't check state
Handle
gpersoon
Vulnerability details
Impact
The function claim() of Pool.sol doesn't include a call to _isValidState(...)
So the function might be called in all states, for example when state=Deactivated
The most of the other functions in Pool.sol do check _isValidState().
Proof of Concept
_isValidState is not present here:
function claim(address loan, address dlFactory) external returns(uint256[7] memory) {
_whenProtocolNotPaused();
_isValidDelegateOrAdmin();
uint256[7] memory claimInfo = IDebtLocker(debtLockers[loan][dlFactory]).claim();
Tools Used
editor
Recommended Mitigation Steps
Double check if the state is really not relevant here.
Perhaps add a comment that the state is not relevant.
Dangerous operator in require of setLockupPeriod in StakeLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
The require statement on L120 of StakeLocker.sol checks if the newLockupPeriod is ‘<=‘ current lockupPeriod presumably to ensure that pool delegate cannot suddenly increase it to lock up stakes funds longer than initially agreed. However, without any validation, this could be accidentally set to a new value that is lower than desired e.g. 0. Because of the <=
check, this can only be reduced later and never increased without contract redeployment.
Proof of Concept
Tools Used
Manual analysis
Recommended Mitigation Steps
Perform input validation on newLockupPeriod e.g. != 0 or not less than some bound.
Missing event for critical operation of new Debt locker creation in DebtLockerFactory.sol
Handle
0xRajeev
Vulnerability details
Impact
Lockers are critical contracts that hold custody of different Maple assets. While there are five lockers created initially (as described in https://github.com/maple-labs/maple-core/wiki/Lockers), such new lockers created by the factory should be logged as events for off-chain monitoring, similar to whats done in StakeLocker. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log locker creation.
Missing input validation on function parameter for zero address in CollateralLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended especially when they are used in token transfers. Zero-address check is missing on the dst parameter of the pull() function in CollateralLocker.sol.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Perform zero address input validation on dst parameter.
tricky evaluation > and +
Handle
gpersoon
Vulnerability details
Impact
The evaluation of a > b + c is tricky because it depends on the compiler implementation. It could evaluate as:
(a > b) + c or a > (b + c)
Proof of Concept
This evaluation is done here:
PoolLib.sol: return block.timestamp > withdrawCooldown + globals.lpCooldownPeriod() + globals.lpWithdrawWindow();
Tools Used
grep " > " *.sol -S
Recommended Mitigation Steps
Add parenthesis:
return block.timestamp > (withdrawCooldown + globals.lpCooldownPeriod() + globals.lpWithdrawWindow());
State variables not explicitly initialized
Handle
gpersoon
Vulnerability details
Impact
The "State" variables not explicitly initialized, in Loan.sol and Pool.sol.
This could be tricky if states are added to the, especially in the beginning.
It's also not clear for the casual reviewer what the initial state is.
Proof of Concept
Loan.sol: enum State { Ready, Active, Matured, Expired, Liquidated }
Loan.sol: State public loanState; // The current state of this loan, as defined in the State enum below
Pool.sol: enum State { Initialized, Finalized, Deactivated }
Pool.sol: State public poolState;
Tools Used
Review of the code
Recommended Mitigation Steps
Explicitly initialize enum type variables or add a comment indicating the initial state.
Missing input validation on function parameter for zero address in FundingLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended especially when they are used in token transfers. Zero-address check is missing on the dst parameter of the pull() function in FundingLocker.sol.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Perform zero address input validation on dst parameter.
Inconsistent NatSpec comment in DebtLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Access control of external/public functions via modifiers or require statements is typically specified in the @dev part of the NatSpec comment. This highlight is missing for the claim() function which is accessible only by isPool.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Add “Only called by the pool contract.” to @dev on L45.
Inconsistent NatSpec comment in StakeLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Function _isValidPoolDelegate() is not about pause/unpause but about msg.sender being a valid Pool Delegate, which is used to check if msg.sender can set lockup period and open staking to public in StakeLocker.sol.
Therefore, the Natspec comment for this function is incorrect:
@dev Function to determine if msg.sender is eligible to trigger pause/unpause.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Change @dev Natspec comment to correctly indicate the functionality of _isValidPoolDelegate().
Loans of tokens with >18 decimals can result in incorrect collateral calculation
Handle
0xsomeone
Vulnerability details
Impact
It is possible for a user to mislead a Pool Delegate to a seemingly innocuous loan by utilizing a token with more than 18 decimals as collateral and lucrative loan terms.
Proof of Concept
The final calculation within the collateralRequiredForDrawdown
of LoanLib
incorrectly assumes the collateral token of a loan to be less than 18
decimals, which can not be the case as there is no sanitization conducted on the creation of a Loan
via the factory. This can cause an underflow to the power of 10
which will cause the division to yield 0
and thus cause the Loan
to calculate 0
as collateral required for the loan.
Line in question: https://github.com/maple-labs/maple-core/blob/031374b2609560ade825532474048eb5826dec20/contracts/library/LoanLib.sol#L235
Tools Used
Manual review.
Recommended Mitigation Steps
We advise the same paradigm as _toWad
to be applied which is secure: https://github.com/maple-labs/maple-core/blob/031374b2609560ade825532474048eb5826dec20/contracts/library/LoanLib.sol#L247
Anyone can use the locker factories
Handle
gpersoon
Vulnerability details
Impact
Anyone can call the newLocker function in the *LockerFactory.sol contracts to create a new contract.
This makes later checks if the contract has been created by the factory (e.g. isValidSubFactory) less useful.
This might be a step in using other vulnerabilities.
Proof of Concept
CollateralLockerFactory.sol: function newLocker(address collateralAsset) external returns (address) {
DebtLockerFactory.sol: function newLocker(address loan) external returns (address) {
FundingLockerFactory.sol: function newLocker(address liquidityAsset) public returns (address) {
LiquidityLockerFactory.sol: function newLocker(address liquidityAsset) external returns (address) {
StakeLockerFactory.sol: function newLocker(address stakeAsset,address liquidityAsset) external returns (address) {
MapleGlobals.sol:
function isValidSubFactory(address superFactory, address subFactory, uint8 factoryType) external view returns(bool) {
return validSubFactories[superFactory][subFactory] && ISubFactory(subFactory).factoryType() == factoryType;
}
Tools Used
Editor
Recommended Mitigation Steps
Check if this is the intended behaviour and add additional checks if required.
Missing event for critical operation of Pool Delegate validity change in MapleGlobals.sol
Handle
0xRajeev
Vulnerability details
Impact
Pool delegates are trusted actors (see https://github.com/maple-labs/maple-core/wiki/Security#trust-assumptions) and so any change (additions/removals) in their validity should be recorded for off-chain monitoring. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log pool delegate validity change in setPoolDelegateAllowlist function.
Several TODO action points left in the code
Handle
gpersoon
Vulnerability details
Impact
Several TODO action points left in the code, which could lead to unexpected results if not finished.
Also best practice to finish/remove them.
Proof of Concept
Pool.sol: emit Claim(loan, interestClaim, principalClaim, claimInfo[3]); // TODO: Discuss with offchain team about requirements for event
Pool.sol: return claimInfo; // TODO: Discuss with offchain team about requirements for return
Pool.sol: // TODO: Do we need PoolFDT BalanceUpdated events?
StakeLocker.sol: lockupPeriod = 180 days; // TODO: Confirm default
PoolLib.sol: // TODO: Consider renaming this - could be mistaken for Pool claimable funds, not LP claimable
Loan.t.sol: uint256 paymentIntervalDays = paymentIntervalArray[index % 10]; // TODO: Consider changing this approach
ERC2222.sol: * and try to distribute it in the next distribution ....... todo implement
Tools Used
grep -i todo *.sol -S
Recommended Mitigation Steps
Check and followup or remove the todo's
Incorrect input validation on the most critical admin role in the protocol in MapleGlobals.sol
Handle
0xRajeev
Vulnerability details
Impact
The global admin defined in MapleGlobals is the most critical admin in the protocol as indicated in the comment on L20 of MapleGlobals.sol: “Admin of the whole network, has the power to switch off/on the functionality of entire protocol.”
This admin address is set on L89 of the constructor without any input validation. But more importantly, the setAdmin function which is callable only by the protocol Governor has an incorrect input validation on L151:
require(msg.sender == governor && admin != address(0), "MapleGlobals:UNAUTHORIZED");
where, instead of checking the parameter newAdmin against zero address, the require statement checks the existing admin variable against zero address.
This incorrect check allows newAdmin to be a zero address which is then assigned to admin. This flow will prevent the pausing/unpausing of the protocol because of the check on L183 in setProtocolPause. Furthermore, this one time mistake of setting the admin to zero-address cannot be fixed (without contract redeployment) because of the incorrect check on L151 (indicated above) which will now trigger for zero-address of admin.
Proof of Concept
admin variable: https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L20
Incorrect input validation: https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L153
Use of admin in pausing/unpausing: https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L185
Tools Used
Manual Analysis
Recommended Mitigation Steps
Change admin to newAdmin on L151:
require(msg.sender == governor && newAdmin != address(0), "MapleGlobals:UNAUTHORIZED");
Loans Cannot Be Re-Funded
Handle
0xsomeone
Vulnerability details
Impact
Due to an incorrect invocation of safeApprove
in fundLoan
of LiquidityLocker
, it is not possible to fund a loan twice for different amounts.
Proof of Concept
The safeApprove
function of OpenZeppelin enforces that non-zero approvals can only be done for zeroed out ones, meaning that if an approval is set to a non-zero value it must be re-set to zero before being adjusted to another non-zero value. This is not the case of the fundLoan
function in LiquidityLocker
: https://github.com/maple-labs/maple-core/blob/031374b2609560ade825532474048eb5826dec20/contracts/LiquidityLocker.sol#L43
Tools Used
Manual Review.
Recommended Mitigation Steps
This is a misbehaviour of the system and as such, we advise the adjustment of the code block to zero out the approval first if it is non-zero.
Year is not exactly 365 days
Handle
gpersoon
Vulnerability details
Impact
The function getNextPayment in RepaymentCalc.sol makes a calculation based on 365 days.
However a year does not exactly contain 365 days, depending on it being a leap year.
So the calculations might be slightly off.
Proof of Concept
RepaymentCalc.sol:
function getNextPayment(address _loan) view public returns(uint256, uint256, uint256) {
..
uint256 interest =
principalOwed
.mul(loan.apr())
.mul(loan.paymentIntervalSeconds())
.div(10_000)
.div(365 days);
Tools Used
Editor
Recommended Mitigation Steps
Check if the difference for leap years is relevant. Perhaps add a comment if the difference is ignored.
MapleTreasury does not emit an event when MapleGlobals address is updated
Handle
JMukesh
Vulnerability details
Impact
Its impact will be limited since we will not able tract the change of address off-chain but on-chain we can which will consume gas
Proof of Concept
In file MapleTreasury.sol has no event, so it is difficult to track off-chain changes of Address of new MapleGlobals contract
Tools Used
slither
Recommended Mitigation Steps
add event for setting global address
No renounce function for the admin role
Handle
JMukesh
Vulnerability details
Impact
Its impact will be on entire protocol, since admin has power to switch off/on functionality of entire protocol.
Proof of Concept
In loan.sol, MappleGlobal.sol, Pool.sol, PoolFactory.sol, there is a function for setting an admin, but what if admin want to renounce its role. Since there is no function through which admin can renounce its role, governor end up setting new admin while old admin is still active.
Tools Used
No tool Used
Recommended Mitigation Steps
Introduce a function through which admins can renounce their role
Declare functions `external` to save gas
Handle
JMukesh
Vulnerability details
// All these function described should be declared external, as functions that are never called by the contract should be declared external to save gas.
In fundingLockerFactory.sol --> newLocker(){}
In LatefeeCalc.sol --> getlateFee(){]
In Loan.sol --> MakeFullPayment(){}
In library/Loanlib.sol --> getNextPayment(){}
In library/Util.sol --> calcMinAmount(){}
In token/BasicFDT.sol --> withdrawnFundsOf(){}
In MapleTreasury.sol --> reclaimERC20(){}
distributeToHolder(){}
convertERC20(){}
In Pool.sol --> claimablefunds(){}
--> BPTval(){}
In Poollib,sol --> validateDeactivation(){}
isWithdrawAllowed(){}
getInitialStakeRequirements(){}
ecognizedLossesOf(){}
In Premiumcal.sol --> getPremium(){}
In Repayment.sol --> getNextPayment(){}
Typo NULL_TRASNFER_DST
Handle
gpersoon
Vulnerability details
Impact
A require statement in the function transfer in LiquidityLocker.sol contains a typo.
TRASNFER should be TRANSFER
Proof of Concept
LiquidityLocker.sol: function transfer(address dst, uint256 amt) external isPool {
LiquidityLocker.sol: require(dst != address(0), "LiquidityLocker:NULL_TRASNFER_DST");
Tools Used
Editor
Recommended Mitigation Steps
Fix typo
Missing input validation on critical globals variable for zero address in PoolFactory.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended. This becomes especially critical for parameters which cannot be later changed (if/when zero addresses are used mistakenly) and will force redeployment of contracts.
The setGlobals() function does not input validate the newGlobals parameter for zero address. Using a zero address accidentally here cannot be corrected by calling setGlobals() again because it is access protected by _isValidGovernor() check which itself uses the globals variable to access the governor address. Such an accidental zero-address assignment will force contract redeployment.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Add zero address input validation on all address parameters, especially the critical ones which cannot be reset later such as the globals address.
Inconsistent NatSpec comment in StakeLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Function _isValidAdminOrPoolDelegate() is not about pause/unpause but about msg.sender being valid Admin or Pool Delegate, which is used by pause/unpause in StakeLocker.sol.
Therefore, the Natspec comment for this function is incorrect:
@dev Function to determine if msg.sender is eligible to trigger pause/unpause.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Change @dev Natspec comment to correctly indicate the functionality of _isValidAdminOrPoolDelegate().
Missing event for critical operation of new Collateral locker creation in CollateralLockerFactory.sol
Handle
Vulnerability details
Impact
Lockers are critical contracts that hold custody of different Maple assets. While there are five lockers created initially (as described in https://github.com/maple-labs/maple-core/wiki/Lockers), such new lockers created by the factory should be logged as events for off-chain monitoring, similar to whats done in StakeLocker. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log locker creation.
Missing input validation on critical globals variable for zero address in MapleTreasury.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended. This becomes especially critical for parameters which cannot be later changed (if/when zero addresses are used mistakenly) and will force redeployment of contracts.
The setGlobals() function does not input validate the newGlobals parameter for zero address. Using a zero address accidentally here cannot be corrected by calling setGlobals() again because it is access protected by isGovernor modifier which itself uses the globals variable to access the governor address. Such an accidental zero-address assignment will force contract redeployment.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Add zero address input validation on all address parameters, especially the critical ones which cannot be reset later such as the globals address.
Unused definition of enum
Handle
gpersoon
Vulnerability details
Impact
LoanLib.sol has a definition of enum State and Loan.sol has the same definition.
The LoanLib.sol does not seem to be used
This means dead code and could be confusing.
Proof of Concept
Loan.sol: enum State { Ready, Active, Matured, Expired, Liquidated }
LoanLib.sol: enum State { Ready, Active, Matured, Expired, Liquidated }
Tools Used
grep "enum" *.sol -S
Recommended Mitigation Steps
Remove the unused definition from LoanLib.sol
(or make sure there is just one definition for the enum and include that elsewhere)
Missing zero address validation
Handle
JMukesh
Vulnerability details
Impact
If contract miss this zero check address validation there is chance that contract will loose some functionality
Proof of Concept
debtLocker.sol, fundingLocker.sol, FundingLockerFactory.sol, liquidyLocker.sol, LiquidyLockerFactory.sol, Loan.sol, MapleGlobal.sol, MapleTreasury.sol, Pool.sol, PoolFactory.sol, stakelocker.sol all these files lack zero-check address due to which they can loose some of the functionality for ex :-
In PoolFactory.sol
constructor(address _globals) public {
globals = IGlobals(_globals);
}
it mises zero check address due to which we will not be able set globals
Tools Used
No tool used
Recommended Mitigation Steps
Introduce the function which check zero address
Multiple pause mechanisms (#3)
Handle
gpersoon
Vulnerability details
This is an addition to the previous issue: Multiple pause mechanisms
Impact
There is a third pause mechanism in MplRewards.sol, via the function _notPaused();
Note the other 2 puase mechanisms are:
modifier whenNotPaused from openzeppelin Pausable.sol
function _whenProtocolNotPaused()
It is confusing to have multiple mechanisms for the same goal.
Proof of Concept
MplRewards.sol
function _notPaused() internal view {
require(!paused, "REWARDS:CONTRACT_PAUSED");
}
Tools Used
editor
Recommended Mitigation Steps
Simplify the pause mechanisms
Missing event for critical operation of setAdmin change for Protocol admin in MapleGlobals.sol
Handle
0xRajeev
Vulnerability details
Impact
The protocol admin defined in MapleGlobals can pause/unpause all important functionalities of the protocol. This critical operation of admin status change in setAdmin function should be logged as an event for off-chain monitoring. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log admin status change in setAdmin function.
Missing input validation on critical globals for zero addresses in MapleGlobals.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended. This becomes especially critical for parameters which cannot be later changed (if/when zero addresses are used mistakenly) and will force redeployment of contracts.
The constructor of MapleGlobals does not input validate the governor, Maple protocol token or admin parameters for zero addresses. While admin can be reset via setAdmin, Maple protocol token or the critical governor address that is the most significant address for access control in the protocol, cannot be reset and will require contract redeployment. Changing the governor address via setPendingGovernor+acceptGovernor itself requires the calling account to be a valid governor account which is not the case for a zero address.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Add zero address input validation on all address parameters, especially the critical ones which cannot be reset later such as the governor address.
Cross-Chain Replay Attack
Handle
0xsomeone
Vulnerability details
Impact
The constructor
of the Maple token calculates the chainid
it should assign during its execution and permanently stores it in an immutable
variable. Should Ethereum fork in the feature, the chainid
will change however the one used by the permits will not enabling a user to use any new permits on both chains thus breaking the token on the forked chain permanently.
Proof of Concept
Please consult EIP1344 for more details: https://eips.ethereum.org/EIPS/eip-1344#rationale
Tools Used
Manual review.
Recommended Mitigation Steps
The mitigation action that should be applied is the calculation of the chainid
dynamically on each permit
invocation. As a gas optimization, the deployment pre-calculated hash for the permits can be stored to an immutable
variable and a validation can occur on the permit
function that ensure the current chainid
is equal to the one of the cached hash and if not, to re-calculate it on the spot.
Same constants defined in different files
Handle
gpersoon
Vulnerability details
Impact
The some constants are defined in different files. This has that if it is changed in one place it is forgotten to change at the other place.
Proof of Concept
MapleGlobals.sol: 0 = COLLATERAL_LOCKER_FACTORY
MapleGlobals.sol: 1 = DEBT_LOCKER_FACTORY
MapleGlobals.sol: 2 = FUNDING_LOCKER_FACTORY
MapleGlobals.sol: 3 = LIQUIDUITY_LOCKER_FACTORY
MapleGlobals.sol: 4 = STAKE_LOCKER_FACTORY
LoanFactory.sol: uint8 public constant CL_FACTORY = 0; // Factory type of CollateralLockerFactory
Pool.sol: uint8 public constant DL_FACTORY = 1; // Factory type of DebtLockerFactory
LoanFactory.sol: uint8 public constant FL_FACTORY = 2; // Factory type of FundingLockerFactory
PoolFactory.sol: uint8 public constant LL_FACTORY = 3; // Factory type of LiquidityLockerFactory
PoolFactory.sol: uint8 public constant SL_FACTORY = 4; // Factory type of StakeLockerFactory
CollateralLockerFactory.sol: uint8 public constant factoryType = 0; // i.e FactoryType::COLLATERAL_LOCKER_FACTORY
DebtLockerFactory.sol: uint8 public constant factoryType = 1; // i.e LockerFactoryTypes::DEBT_LOCKER_FACTORY
FundingLockerFactory.sol: uint8 public constant factoryType = 2; // i.e FactoryType::FUNDING_LOCKER_FACTORY
LiquidityLockerFactory.sol: uint8 public constant factoryType = 3; // i.e LockerFactoryTypes::LIQUIDITY_LOCKER_FACTORY
StakeLockerFactory.sol: uint8 public constant factoryType = 4; // i.e FactoryType::STAKE_LOCKER_FACTORY.
LoanFactory.sol: uint8 public constant INTEREST_CALC_TYPE = 10; // Calc type of RepaymentCalc
LoanFactory.sol: uint8 public constant LATEFEE_CALC_TYPE = 11; // Calc type of LateFeeCalc
LoanFactory.sol: uint8 public constant PREMIUM_CALC_TYPE = 12; // Calc type of PremiumCalc
RepaymentCalc.sol: uint8 public constant calcType = 10; // INTEREST type
LateFeeCalc.sol: uint8 public constant calcType = 11; // "LATEFEE type"
PremiumCalc.sol: uint8 public constant calcType = 12; // PREMIUM type
Tools Used
grep
Recommended Mitigation Steps
Define constants in one file and include them when needed.
Also consider using enums.
Attackers Can Steal Any MPL That Is Burned/Sent To 0x000...000
Handle
jvaqa
Vulnerability details
Impact
Any MPL that is sent to 0x000...000 is available to be stolen by anyone.
When ecrecover() is given an incorrect signature, it fails silently and returns a zero address (see the second paragraph of Security Considerations at EIP 2612).
The MPL token's implementation of permit() in MapleToken.sol includes an ecrecover call, but does not check to ensure that ecrecover returns a non-zero result.
Thus, an attacker can call permit with address(0) as the owner and themselves as the spender.
This will give the attacker approval to spend any MPL that is owned by the zero address.
The zero address may own MPL due to it being burned, or due to an accident, or for some other reason.
Proof of Concept
An attacker Alice makes two calls:
(1) MPL.permit(address(0), address(aliceAddress), UINT256MAX, UINT256MAX, 0, 0x0, 0x0);
(2) MPL.transferFrom(address(0), address(aliceAddress), MPL.balanceOf(address(0)));
The first call will give Alice unlimited approval to transfer all MPL owned by the zero address.
The second call will transfer all MPL owned by the zero address to Alice.
Recommended Mitigation Steps
In MapleToken.sol, change this:
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress == owner, 'MapleToken:INVALID_SIGNATURE');
To this:
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress == owner, 'MapleToken:INVALID_SIGNATURE');
require(recoveredAddress != address(0), "MapleToken:ZERO_ADDRESS_IS_INVALID");
Missing event for critical operation of setAdmin change in Loan.sol
Handle
0xRajeev
Vulnerability details
Impact
An admin of a Loan can pause/unpause the fundLoan operation along with the borrower. This critical operation of admin status change in setAdmin function should be logged as an event for off-chain monitoring. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log admin status change in setAdmin function.
External and public not used consistently
Handle
gpersoon
Vulnerability details
Impact
Several function are defined to be public and others are external.
Even with very similar functions the use of public and external differs.
Making this the same everywhere (where possible) will make the code cleaner
Proof of Concept
LoanFactory.sol:
function createLoan(..) external whenNotPaused returns (address) {
PoolFactory.sol:
function createPool(..) public whenNotPaused returns (address) {
Tools Used
editor
Recommended Mitigation Steps
Use public and external in a consistent way
nonReentrant is missing compared to original
Handle
gpersoon
Vulnerability details
Impact
MplRewards.sol is based on the StakingRewards.sol contract of Synthetixio
However the original contains the modifier nonReentrant and MplRewards.sol doesn't.
I don't see any major issue here but is not logical to remove safety mechanisms.
Proof of Concept
MplRewards.sol
function withdraw(uint256 amount) public {
_notPaused();
_updateReward(msg.sender);
... }
https://github.com/Synthetixio/synthetix/blob/v2.41.0/contracts/StakingRewards.sol
function withdraw(uint256 amount) public nonReentrant updateReward(msg.sender) {
}
Tools Used
Source review
Recommended Mitigation Steps
Consider to add nonReentrant or add a comment why it can be left out.
Inconsistent NatSpec comment in StakeLocker.sol
Handle
0xRajeev
Vulnerability details
Impact
Access control of external/public functions via modifiers or require statements is typically specified in the @dev part of the NatSpec comment. This highlight is missing for the pull() function of StakeLocker.sol which is accessible only by isPool.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Add “Only Pool can call this function.” to @dev on L126.
Multiple pause mechanisms
Handle
gpersoon
Vulnerability details
Impact
Two different pause mechanisms are used
One with the modifier whenNotPaused from openzeppelin Pausable.sol
And one via the function _whenProtocolNotPaused()
The could lead to confusion, especially because the names are very similar.
Proof of Concept
Loan.sol: function fundLoan(address mintTo, uint256 amt) whenNotPaused external {
LoanFactory.sol: ) external whenNotPaused returns (address) {
PoolFactory.sol: ) public whenNotPaused returns (address) {
StakeLocker.sol: function stake(uint256 amt) whenNotPaused external {
Loan.sol: function _whenProtocolNotPaused() internal {
LoanFactory.sol: function _whenProtocolNotPaused() internal {
Pool.sol: function _whenProtocolNotPaused() internal {
PoolFactory.sol: function _whenProtocolNotPaused() internal {
StakeLocker.sol: function _whenProtocolNotPaused() internal {
Tools Used
grep
Recommended Mitigation Steps
Doublecheck the need for multiple mechanism.
Perhaps change the name of _whenProtocolNotPaused() to be more different from whenNotPaused
Missing event for critical operation of new Liquidity locker creation in LiquidityLockerFactory.sol
Handle
0xRajeev
Vulnerability details
Impact
Lockers are critical contracts that hold custody of different Maple assets. While there are five lockers created initially (as described in https://github.com/maple-labs/maple-core/wiki/Lockers), such new lockers created by the factory should be logged as events for off-chain monitoring, similar to whats done in StakeLocker. However, such an event emission is missing here.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Create and emit a suitable event to log locker creation.
Missing input validation on critical globals variable for zero address in LoanFactory.sol
Handle
0xRajeev
Vulnerability details
Impact
Input validation on address parameters checking for zero addresses is always recommended. This becomes especially critical for parameters which cannot be later changed (if/when zero addresses are used mistakenly) and will force redeployment of contracts.
The setGlobals() function does not input validate the newGlobals parameter for zero address. Using a zero address accidentally here cannot be corrected by calling setGlobals() again because it is access protected by _isValidGovernor() check which itself uses the globals variable to access the governor address. Such an accidental zero-address assignment will force contract redeployment.
Proof of Concept
Tools Used
Manual Analysis
Recommended Mitigation Steps
Add zero address input validation on all address parameters, especially the critical ones which cannot be reset later such as the globals address.
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.