xanoutas/solidity-security-findings huggingface dataset:
Upgraded Q -> 2 from #481 [1706648292480]
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

Judge has assessed an item in Issue #481 as 2 risk. The relevant finding follows:

 # 5, Attacker can front run distribute reward from GUILD token and steal newly added rewards
## Lines of code
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/SurplusGuildMinter.sol#L114-#L212
## Vulnerability details 
Every time the `notifyPnL()` get called, if in the config, there is a part of token distribute for guild, there will be credit token distribute for guild holder:

            if (amountForGuild != 0) {
                uint256 _gaugeWeight = uint256(GuildToken(guild).getGaugeWeight(gauge));
                if (_gaugeWeight != 0) {
                    uint256 _gaugeProfitIndex = gaugeProfitIndex[gauge];
                    if (_gaugeProfitIndex == 0) {
                        _gaugeProfitIndex = 1e18;
                    }
                    gaugeProfitIndex[gauge] = _gaugeProfitIndex + (amountForGuild * 1e18) / _gaugeWeight;
                }

This enables a well-known attack vector, in which the attacker will deposit peg token to get credit token, stake them and unstake right after claim reward. 
## Impact
Not everytime user can claim reward and get profit like this, it depend alot about other factor: total credit token can be minted by `RateLimitedMinter`, total profit gained, ....., but the attack effectively steal the part of the newly added rewards
## Recommendation
Reward distribute by staking guild token should be distributed like credit token rebasing,
Upgraded Q -> 2 from #332 [1706646042460]
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

Judge has assessed an item in Issue #332 as 2 risk. The relevant finding follows:

 ## params.maxDelayBetweenPartialRepay should never be zero
In [LendingTerm.partialRepayDelayPassed](https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/LendingTerm.sol#L241), the code makes it return false if maxDelayBetweenPartialRepay is set to 0, which stands to reason. However, due to this, that value will prevent anyone from calling an underwater loan, unless the entire gauge gets deprecated, which seems pretty drastic. We recommend never to allow this parameter to be zero, considering how easy it is to get bad debt and require the gauge to be deprecated.
Upgraded Q -> 2 from #258 [1706642045293]
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

Judge has assessed an item in Issue #258 as 2 risk. The relevant finding follows:

 [L-10] There is a potential for underflow in the `decreaseUnmintedRebaseRewards` function within the `ERC20RebaseDistributor` token.

When updating shares, we adjust the share price accordingly.
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/tokens/ERC20RebaseDistributor.sol#L213-L217
```
function updateTotalRebasingShares() {
    uint256 delta = uint256(val.targetValue) - currentRebasingSharePrice;
    if (delta != 0) {
        uint256 percentChange = (sharesAfter * START_REBASING_SHARE_PRICE) / sharesBefore;
        uint256 targetNewSharePrice = currentRebasingSharePrice + (delta * START_REBASING_SHARE_PRICE) / percentChange;
}
```
No need to calculate `percentChange`; the updated price will be as follows:
```
targetNewSharePrice = currentRebasingSharePrice + delta * sharesBefore / sharesAfter```
```
Due to rounding, the calculated price may be slightly larger. 
Consequently, when attempting to decrease unminted rewards, there is a risk of underflow.
```
function decreaseUnmintedRebaseRewards(uint256 amount) internal {
    lastValue: SafeCastLib.safeCastTo224(
        _unmintedRebaseRewards - amount
    ), // adjusted current
}
```
Upgraded Q -> 2 from #258 [1706641869227]
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

Judge has assessed an item in Issue #258 as 2 risk. The relevant finding follows:

 [L-9] Any borrower can receive `rewards` by adding weight to the `term` before repayment.

When interests accrue from borrowers, these interests are immediately distributed to token holders based on their respective weights.
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/governance/ProfitManager.sol#L396-L399
```
function notifyPnL() {
    gaugeProfitIndex[gauge] = _gaugeProfitIndex + (amountForGuild * 1e18) / _gaugeWeight;
}
```
Hence, any borrower can add weight before repayment, receive `rewards`, and subsequently withdraw their added weight.
Need a logic similar to rebasing tokens.
Upgraded Q -> 2 from #258 [1706641667381]
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

Judge has assessed an item in Issue #258 as 2 risk. The relevant finding follows:

 [L-8] Please use `targetTotalSupply` instead of `totalSupply`.

When applying `loss`, we calculate the `newCreditMultiplier` based on the `loss` and total supply.
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/governance/ProfitManager.sol#L331-L333
```
function notifyPnL() {
    uint256 creditTotalSupply = CreditToken(_credit).totalSupply();
    uint256 newCreditMultiplier = (creditMultiplier *
        (creditTotalSupply - loss)) / creditTotalSupply;
}
```
If there are unminted tokens, the correct total supply should be `targetTotalSupply`.
Upgraded Q -> 2 from #556 [1706627592320]
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

Judge has assessed an item in Issue #556 as 2 risk. The relevant finding follows:

 ## [L-04] `debtCeiling()` does not properly calculate the debt ceiling of gauges experiencing an adjustment up

### Bug Description
The `debtCeiling` function will return a gauge's debt allocation, with respect to an applied adjustment (gauge is being staked into or unstaked from):

[LendingTerm::debtCeiling#L270-L281](https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/LendingTerm.sol#L270-L281)
```solidity
270:    function debtCeiling(
271:        int256 gaugeWeightDelta
272:    ) public view returns (uint256) {
273:        address _guildToken = refs.guildToken; // cached SLOAD
274:        uint256 gaugeWeight = GuildToken(_guildToken).getGaugeWeight(
275:            address(this)
276:        );
277:        gaugeWeight = uint256(int256(gaugeWeight) + gaugeWeightDelta);
278:        uint256 gaugeType = GuildToken(_guildToken).gaugeType(address(this));
279:        uint256 totalWeight = GuildToken(_guildToken).totalTypeWeight(
280:            gaugeType
281:        );
```

As seen above, the `gaugeWeightDelta` is the adjustment being applied to the `gaugeWeight` of the gauge. If the adjusted `gaugeWeight` is 0, then the debt ceiling is considered 0. If the `gaugeWeight` is equal to the `totalWeight` for all the gauge's of this type, then the gauge is considered to have 100% debt allocation:

[LendingTerm::debtCeiling#L285-L292](https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/loan/LendingTerm.sol#L285-L292)
```solidity
285:        if (gaugeWeight == 0) {
286:            return 0; // no gauge vote, 0 debt ceiling
287:        } else if (gaugeWeight == totalWeight) {
288:            // one gauge, unlimited debt ceiling
289:            // returns min(hardCap, creditMinterBuffer)
290:            return
291:                _hardCap < creditMinterBuffer ? _hardCap : creditMinterBuffer;
292:        }
```

However, as we can see in the above code snippets, the adjusted `totalWeight` for the gauge type is not considered. This can result in a gauge being adjusted up by a `gaugeWeightDelta` that results in the adjusted `gaugeWeight` being equal to the non-adjusted `totalWeight`. If this gauge is in a multi-gauge system then it's calculated debt allocation will be considered 100%, despite the weight of other gauges in the system. Lets consider an example:

```
- totalWeight = 2000e18
- Gauge A weight =  1000e18 => 50% debt allocation
- Gauge B weight = 1000e18 => 50% debt allocation

- gaugeA.debtCeiling(1000e18):
- gaugeWeightDelta = 1000e18
- gaugeWeight = gaugeAWeight + gaugeWeightDelta = 2000e18
- gaugeWeight == totalWeight => 100% debt allocation

Actual debt allocations after adjustment:
- totalWeight (post adjustment) = 3000e18
- Gauge A weight (post adjustment) = 2000e18
- Gauge B weight = 1000e18

- Gauge A debt allocation = 2000e18 / 3000e18 => ~ 66%
- Gauge B debt allocation = 1000e18 / 3000e18 => ~ 33%
```

As we can see
Quorum can be changed between proposal creation and execution
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/GuildGovernor.sol#L57-L71
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/GuildVetoGovernor.sol#L53-L64


# Vulnerability details

## Impact

In both the GuildGovernor and GuildVetoGovernor contract the quorum can be changed between the time of a proposal creation time and its execution which may potentially impact the acceptance or refusal of certain proposals

## Proof of Concept

The ability to change the `quorum` value between the creation and execution of proposals can lead to the following issues:

- **Proposal Integrity**: The dynamic nature of the quorum allows for manipulation of the voting requirements, potentially impacting the integrity of the proposal acceptance process.
  
- **Unpredictable Governance**: The lack of a fixed quorum for each block number introduces uncertainty in the governance process, making it difficult for participants to anticipate the voting requirements at the time of proposal execution.

The vulnerability is evident in the following code snippet:

```solidity
/// @notice The minimum number of votes needed for a vote to pass.
function quorum(uint256 /* blockNumber */) public view override returns (uint256) {
    //@audit quorum can be changed between the proposals creation and execution time which may affect the proposal acceptance or refusal, should instead have a quorum for each block number
    return _quorum;
}
```

The absence of a specific quorum value for each block number allows the `_quorum` value to be modified without restrictions, potentially leading to governance inconsistencies.

## Tools Used

Manual review

## Recommended Mitigation Steps

To address this vulnerability and enhance the security of the governance contract, it is recommended to implement a fixed quorum for each block number. This can be achieved by maintaining a mapping of block numbers to their corresponding quorum values. The `quorum` function should then retrieve the appropriate quorum value based on the block number provided.

Example:

```solidity
mapping(uint256 => uint256) private _blockNumberQuorums;

function setQuorum(uint256 blockNumber, uint256 newQuorum) external onlyOwner {
    _blockNumberQuorums[blockNumber] = newQuorum;
}

function quorum(uint256 blockNumber) public view override returns (uint256) {
    return _blockNumberQuorums[blockNumber];
}
```

This modification ensures that the quorum is fixed for each block number, providing a more secure and predictable governance process.

The governance contract allows the dynamic modification of the `quorum` value between the creation and execution of proposals. This flexibility in adjusting the quorum may introduce a security vulnerability, potentially impacting the acceptance or refusal of proposals. It is recommended to establish a fixed quorum for each block number to enhance the security and predictability of the governance process.
Unexpected quorum changes can affect ongoing votes in `GuildVetoGovernor.sol`
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/GuildVetoGovernor.sol#L53-L57


# Vulnerability details

## Impact
The `quorum` function in the `GuildVetoGovernor.sol` contract ignores the `blockNumber` parameter. This means that the quorum can be modified while a vote is ongoing. This could potentially lead to unexpected behavior, as users may have voted differently if the quorum was different at the time of their vote.

The `quorum` function is designed to return the minimum number of votes needed for a vote to pass. However, due to the lack of consideration for the `blockNumber`, the quorum can be changed during a vote, which could potentially affect the outcome of the vote.

```solidity
function quorum(
    uint256 /* blockNumber*/
) public view override returns (uint256) {        
    return _quorum;
}
```
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/GuildVetoGovernor.sol#L53-L57

## Proof of Concept
Consider a scenario where Alice and Bob are participating in a vote. Alice votes first when the quorum is set to a certain value. However, before Bob casts his vote, the quorum is changed. This change could potentially affect the outcome of the vote, as Bob may have voted differently if the quorum was the same as when Alice voted.

This issue is present in the `GuildVetoGovernor.sol` file.

## Tools Used
Manual review

## Recommended Mitigation Steps
To mitigate this issue, it is recommended to consider the `blockNumber` when determining the quorum. This could be achieved by storing the quorum value at the time of each vote, ensuring that it remains constant throughout the voting process. This would prevent unexpected changes to the quorum from affecting ongoing votes.


## Assessed type

Governance
Functions with `onlyCoreRole(CoreRoles.GUARDIAN)` modifier will be unavailable when sequencer is down
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

# Lines of code

 https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/GuildGovernor.sol#L110-L117


# Vulnerability details

## Impact
Functions with the `onlyCoreRole(CoreRoles.GUARDIAN)` modifier may become unavailable if the sequencer is down. This issue arises due to the interaction of the `GUARDIAN` role, which is operated by a multisig, with Arbitrum's address aliasing feature. 

While it is possible for Externally Owned Accounts (EOAs) to avoid address [aliasing](https://docs.arbitrum.io/arbos/l1-to-l2-messaging#signed-messages) on transactions submitted to Arbitrum's delayed inbox, the multisig address will still be aliased when interacting with the L2. As a result, the multisig may not be able to pause the protocol, especially during a network outage. This could potentially leave the protocol and its users unprotected in such scenarios.

The affected functions are `pause()` and `unpause()` in `CoreRef.sol`, and `guardianCancel()` in `GuildGovernor.sol`.

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/GuildGovernor.sol#L110-L117
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/core/CoreRef.sol#L57-L64
## Proof of Concept
Consider a scenario where the network is experiencing an outage. In this situation, the `GUARDIAN` role, operated by a multisig, attempts to pause the protocol by calling the `pause()` function. However, due to Arbitrum's address aliasing, the multisig's address is aliased, and the call to `pause()` fails, leaving the protocol and its users exposed.

## Tools Used
Manual review

## Recommended Mitigation Steps
Check for aliased addresses in the `onlyCoreRole` modifier as [recommended](https://docs.arbitrum.io/arbos/l1-to-l2-messaging#address-aliasing) in the Arbitrum documentation.


## Assessed type

Other
Rewards to GUILD token holders are sandwichable
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

# Lines of code

 https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/ProfitManager.sol#L396-L399


# Vulnerability details

## Impact
The `ProfitManager` contract has a potential vulnerability where an attacker can perform a sandwich attack. This vulnerability arises from the way the `notifyPnL` function updates the `gaugeProfitIndex` for the reporting gauge immediately when a positive PnL is reported.

Entry points that call `notifyPnL` with a positive PnL are `LendingTerm.repay()`, `LendingTerm.PartialRepay()`, and in some cases `AuctionHouse.bid()`. Unlike rewards to CREDIT holders, rewards to GUILD holders aren't distributed gradually. This means an attacker can sandwich any of these calls, increasing their weight in this gauge, immediately call `ProfitManager.claimGaugeRewards()` or `SurplusGuildMinter.getRewards()` afterwards to reap the rewards, and then unstake/decrease their weight again.

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/ProfitManager.sol#L396-L399
https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/governance/ProfitManager.sol#L427-L435
## Proof of Concept
An attacker can follow these steps to exploit the vulnerability:

1. Monitor the blockchain for transactions that call `LendingTerm.repay()`, `LendingTerm.PartialRepay()`, or `AuctionHouse.bid()` during the first phase of an auction.
2. When such a transaction is found, the attacker sends a transaction with a higher gas price to increase their weight in the gauge.
3. The attacker then immediately calls `claimGaugeRewards()` or `getRewards()` to claim the rewards.
4. Finally, the attacker unstakes or decreases their weight in the gauge.

This sequence of actions allows the attacker to unfairly claim more rewards than they should be entitled to.

## Tools Used
Manual review

## Recommended Mitigation Steps
To mitigate this vulnerability, consider implementing a mechanism to distribute GUILD rewards gradually, similar to how CREDIT rewards are distributed. This could prevent an attacker from being able to immediately claim rewards after increasing their weight in the gauge. Additionally, consider implementing measures to prevent rapid changes in gauge weight, such as rate limiting or cooldown periods.


## Assessed type

Other
Reward dilution in `ERC20RebaseDistributor` through minimal token distribution
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

# Lines of code

 https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/tokens/ERC20RebaseDistributor.sol#L364


# Vulnerability details

## Impact
In the `ERC20RebaseDistributor` contract, the `distribute` function is designed to distribute tokens proportionately to all rebasing accounts. However, there is a potential issue where anyone can dilute rewards by distributing a minimal amount of tokens (1 wei).

The root cause of this issue lies in the `distribute` function. When a distribution is made, the `endTimestamp` is simply extended up to `block.timestamp + DISTRIBUTION_PERIOD` , which means the current distribution is extended. This allows for a scenario where an attacker could repeatedly distribute a minimal amount of tokens (1 wei), diluting the rewards for other users.

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/main/src/tokens/ERC20RebaseDistributor.sol#L364

## Proof of Concept
Consider the following scenario:

1. A large distribution is ongoing (as an example, halfway through `DISTRIBUTION_PERIOD`), with many users set to receive a significant amount of tokens.
2. An attacker, who has a minimal amount of tokens (1 wei), calls the `distribute` function.
3. Because the `endTimestamp` is simply extended up to `DISTRIBUTION_PERIOD` in each `distribute` call, the attacker's distribution dilutes the rewards that were intended for the other users (in this case, halving them in all future blocks).
4. The attacker can carry out this attack repeatedly, such that the rewards are never fully distributed.

## Tools Used
Manual review

## Recommended Mitigation Steps
A more comprehensive solution could involve interpolating rewards individually for each distribution. This would mean that each distribution, which should be of `DISTRIBUTION_PERIOD` duration, would have its rewards calculated separately. This would prevent the dilution of rewards when a new distribution is made before the end of the current distribution period. However, the gas costs imposed by such an implementation could be prohibitively high, making this an unrealistic solution in practice.

Additionally, the `distribute` function could be restricted to being only callable by the `ProfitManager`. This would not directly fix the issue of reward dilution, but it would prevent a direct attack as per the example scenario. This would add an additional layer of security, as only the `ProfitManager` would be able to call the `distribute` function and potentially dilute rewards.



## Assessed type

Other
the call function also should have the wennotpause modifier too exactly like the borrow function 
Audit: 2023-12-ethereumcreditguild-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-ethereumcreditguild/blob/2376d9af792584e3d15ec9c32578daa33bb56b43/src/loan/LendingTerm.sol#L628


# Vulnerability details

## Impact
the wennotpause modifier in borrow function isshould also be on the call function cause the borrowers might plan to extend loan liquidation and avoid it.

but if the borrow is pause then you should also pause the call to avoid loss for borrower


## Proof of Concept
```solidity

function _call(
        address caller,
        bytes32 loanId,
        address _auctionHouse
    ) internal {
        Loan storage loan = loans[loanId];

        // check that the loan exists
        uint256 borrowTime = loan.borrowTime;
        require(loan.borrowTime != 0, "LendingTerm: loan not found");

        // check that the loan is not already closed
        require(loan.closeTime == 0, "LendingTerm: loan closed");

        // check that the loan is not already called
        require(loan.callTime == 0, "LendingTerm: loan called");

        // check that the loan can be called
        require(
            GuildToken(refs.guildToken).isDeprecatedGauge(address(this)) ||
                partialRepayDelayPassed(loanId),
            "LendingTerm: cannot call"
        );

        // check that the loan has been running for at least 1 block
        require(
            borrowTime < block.timestamp,
            "LendingTerm: loan opened in same block"
        );

        // update loan in state
        uint256 loanDebt = getLoanDebt(loanId);
        loans[loanId].callTime = block.timestamp;
        loans[loanId].callDebt = loanDebt;
        loans[loanId].caller = caller;

        // auction the loan collateral
        AuctionHouse(_auctionHouse).startAuction(loanId, loanDebt);

        // emit event
        emit LoanCall(block.timestamp, loanId);
    }

```

## Tools Used
vs-code
## Recommended Mitigation Steps

consider adding pause modifier in the call function too so avoid unjustlly liquidation  


## Assessed type

Other