GithubHelp home page GithubHelp logo

2021-04-maple-findings's Introduction

Contest findings are submitted to this repo

Typically most findings come in on the last day of the contest, so don't be alarmed at all if there's nothing here but crickets until the end of the contest.

As a sponsor, you have four critical tasks in the contest process:

  1. Handle duplicate issues.
  2. Weigh in on severity.
  3. Respond to issues.
  4. Share your mitigation of findings.

Let's walk through each of these.

Handle duplicates

Because the wardens are submitting issues without seeing each others' submissions, there will always be findings that are clear duplicates. Other findings may use different language which ultimately describes the same issue but from different angles. Use your best judgement in identifying duplicates, and don't hesitate to reach out (via DM) to ask C4 for advice.

  1. Determine the best and most thorough description of the finding among the set of duplicates. (At least a portion of the content of the most useful description will be used in the audit report.)
  2. Close the other duplicate issues and label them with duplicate
  3. Mention the primary issue # when closing the issue so that duplicate issues get linked.

Weigh in on severity

Judges have the ultimate discretion in determining severity of issues as well as whether/how issues are considered duplicates. However, sponsor input is a significant criteria.

If you disagree with a finding's severity, leave the original severity label set by the warden and add the label disagree with severity along with comment indicating your opinion for the judges to review. It is possible for issues to be considered 0 (Non-critical).

Feel free to use the question label to anything you would like additional C4 input on.

Respond to issues

Label each finding as one of these:

  • sponsor confirmed, meaning: "Yes, this is a problem and we intend to fix it.")
  • sponsor disputed, meaning either: "We either not duplicate this issue" or "We disagree that this is an issue at all."
  • sponsor acknowledged, meaning: "Yes, technically the issue is correct, but we are not going to resolve it for xyz reasons."

Note that it isn't necessary to dispute a finding in order to suggest it should be considered of lower or higher severity.

Add any necessary comments explaining your rationale for your evaluation of the issue. Note that when the repo is public after all issues are mitigated, wardens will read these comments.

Share your mitigation of findings

For each non-duplicate finding which you have confirmed, you will want to mitigate the issue before the contest report is made public.

As part of that process, we ask that you create a pull request in your original repo for each finding and link to the PR in the issue the PR resolves. This will allow for complete transparency in showing the work of mitigating the issues found in the contest. Rather than closing the issue, mark it as resolved with that label.

2021-04-maple-findings's People

Contributors

code423n4 avatar sockdrawermoney avatar c4-staff avatar joshuashort avatar

Watchers

Nick Johnson avatar Michael Elliot avatar James Cloos avatar Ashok avatar Satyam Agrawal avatar  avatar

2021-04-maple-findings's Issues

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/StakeLocker.sol#L52

Tools Used

Manual Analysis

Recommended Mitigation Steps

Confirm the correct default value and delete the TODO comment on stake lockup period.

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.

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

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/DebtLockerFactory.sol#L19-L23

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/CollateralLocker.sol#L30

Tools Used

Manual Analysis

Recommended Mitigation Steps

Perform zero address input validation on dst parameter.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/Loan.sol#L409-L413

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log admin status change in setAdmin function.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/FundingLockerFactory.sol#L21-L26

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log locker creation.

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");

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L74-L96

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.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/StakeLocker.sol#L125-L132

Tools Used

Manual Analysis

Recommended Mitigation Steps

Add “Only Pool can call this function.” to @dev on L126.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/StakeLocker.sol#L131

Tools Used

Manual Analysis

Recommended Mitigation Steps

Perform zero address input validation on dst parameter.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleTreasury.sol#L57-L59

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleTreasury.sol#L48-L51

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.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L148-L156

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log admin status change in setAdmin function.

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.

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

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/LiquidityLockerFactory.sol#L19-L24

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log locker creation.

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.

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.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/PoolFactory.sol#L43-L46

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/PoolFactory.sol#L141-L143

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.

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.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/LoanFactory.sol#L50-L53

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/LoanFactory.sol#L152-L154

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.

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

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/StakeLocker.sol#L295-L300

Tools Used

Manual Analysis

Recommended Mitigation Steps

Change @dev Natspec comment to correctly indicate the functionality of _isValidAdminOrPoolDelegate().

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

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

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/DebtLocker.sol#L44-L54

Tools Used

Manual Analysis

Recommended Mitigation Steps

Add “Only called by the pool contract.” to @dev on L45.

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

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 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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/FundingLocker.sol#L30

Tools Used

Manual Analysis

Recommended Mitigation Steps

Perform zero address input validation on dst parameter.

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");

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.

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 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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/CollateralLockerFactory.sol#L21-L26

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log locker creation.

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

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 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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/MapleGlobals.sol#L232-L239

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log pool delegate validity change in setPoolDelegateAllowlist function.

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

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(){}

Missing event for critical operation of new Collateral locker creation in CollateralLockerFactory.sol

Handle

https://twitter.com/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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/CollateralLockerFactory.sol#L21-L26

Tools Used

Manual Analysis

Recommended Mitigation Steps

Create and emit a suitable event to log locker creation.

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());

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/StakeLocker.sol#L113-L123

Tools Used

Manual analysis

Recommended Mitigation Steps

Perform input validation on newLockupPeriod e.g. != 0 or not less than some bound.

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.

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.

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

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

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

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.

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

https://github.com/maple-labs/maple-core/blob/355141befa89c7623150a83b7d56a5f5820819e9/contracts/StakeLocker.sol#L302-L307

Tools Used

Manual Analysis

Recommended Mitigation Steps

Change @dev Natspec comment to correctly indicate the functionality of _isValidPoolDelegate().

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.