xanoutas/solidity-security-findings huggingface dataset:
Incorrect negative yield calculation in `_computeYield`
Audit: 2024-02-spectra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/libraries/PrincipalTokenUtil.sol#L98-L112


# Vulnerability details

## Description
`_computeYield` method calculates the negative yield amount incorrectly in certain edge cases. 

When `_oldIBTRate > _ibtRate` (negative yield scenario), the logic computes `yieldInAssetRay` as the difference between the `actualNegativeYieldInAssetRay` and `expectedNegativeYieldInAssetRay`. 

However, if the actual negative yield amount is larger than expected, this difference will be negative, representing a positive yield amount. This allows attackers to manipulate the parameters to extract extra yield.

**The negative yield calculation subtracts the expected from the actual instead of the other way around.**

## Impact
An arbitrary positive yield can be generated by manipulating input parameters.

## Proof of Concept
This vulnerability could allow attackers to manipulate the negative yield calculation to generate arbitrary positive yield amounts. They can exploit this to extract additional yield tokens from the protocol beyond what they are entitled to.

When `_oldIBTRate > _ibtRate`, `_computeYield` calculates the yield as the difference between `actualNegativeYieldInAssetRay` and  `expectedNegativeYieldInAssetRay`. However, if the actual negative yield is larger than expected, their difference will be negative - representing a positive yield amount.

An attacker can exploit this by:

1. Depositing a small amount into the protocol to mint some PT and YT shares.

2. Manipulating the IBT rate via an oracle or flash loan to make `_oldIBTRate` much higher than `_ibtRate`.

3. When `_computeYield` is called, `actualNegativeYieldInAssetRay` will be large based on the high `_oldIBTRate`. But `expectedNegativeYieldInAssetRay` will be small based on the current low `_ibtRate`. 

4. Their difference will be positive, allowing the attacker to extract extra positive yield.

[File: src/libraries/PrincipalTokenUtil.sol::L98-L112 ](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/libraries/PrincipalTokenUtil.sol#L98-L112)

```solidity
uint256 actualNegativeYieldInAssetRay = _convertToAssetsWithRate( <@ // based on high _oldIBTRate
    userYTBalanceInRay,
    _oldPTRate - _ptRate,
    RayMath.RAY_UNIT,
    Math.Rounding.Floor
);
uint256 expectedNegativeYieldInAssetRay = Math.ceilDiv(           <@// based on low _ibtRate 
    ibtOfPTInRay * (_oldIBTRate - _ibtRate),
    RayMath.RAY_UNIT
);
yieldInAssetRay = expectedNegativeYieldInAssetRay >
    actualNegativeYieldInAssetRay
    ? 0
    : actualNegativeYieldInAssetRay - expectedNegativeYieldInAssetRay;
yieldInAssetRay = yieldInAssetRay.fromRay(
```

By making `actualNegativeYieldInAssetRay` much larger than `expectedNegativeYieldInAssetRay`, their difference becomes positive.

### Summary

The negative yield calculation in `_computeYield` incorrectly subtracts a higher `
Manipulation of the IBT rate could have serious implications for Spectra.
Audit: 2024-02-spectra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L533-L536
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L340-L366
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L533-L536


# Vulnerability details

## Impact
Manipulation of IBT rate can skew user yields in Spectra leading to unauthorized inflation or losses. In how Spectra trusts the IBT vault's rate without validation: [File: src/tokens/PrincipalToken.sol::getIBTRate](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L533-L536) [File: src/tokens/PrincipalToken.sol::updateYield](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L340-L366)

```solidity
function getIBTRate() external view override returns (uint256) {
    (, uint256 _ibtRate) = _getPTandIBTRates(false);
    return _ibtRate;
}

function updateYield(address _user) public override returns (uint256 updatedUserYieldInIBT) {
    (uint256 _ptRate, uint256 _ibtRate) = _updatePTandIBTRates();

    // Uses getIBTRate() to compute user yields
}
```
There are no checks that the rate is strictly derived from the IBT vault's holdings and AMM math.

If an attacker can artificially manipulate the IBT rate by even 10%, it can greatly skew Spectra's yield calculations. Users may suffer losses or inflationary yields.

## Proof of Concept
Spectra directly relies on external IBT vault's rate: [File: src/tokens/PrincipalToken.sol::getIBTRate](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L533-L536) [File: src/tokens/PrincipalToken.sol::updateYield](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L340-L366)

No checks validate the integrity of the rate. 

If an attacker gains control of the IBT vault, arbitrary rate modifications would impact Spectra:

```solidity
function setRate(uint256 rate) {
  ibtRate = rate;
}
```
**Exploitation**

Attacker sets inflated IBT rate -> Spectra integrates inflated rate into yield calculations -> user balances increase.

## Tools Used
Vs

## Recommended Mitigation Steps
Enforce immutable IBT rate derivation from holdings. Circuit breakers on anomalies.



## Assessed type

Invalid Validation
Lack of IBT amount verification enables arbitrage and theft.
Audit: 2024-02-spectra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L430-L438
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L430-L438


# Vulnerability details


## Impact
Not verifying actual IBT amounts against preview values enables arbitrage and theft of assets. An attacker can construct a malicious Vault contract to exploit this.

The issue stems from the fact that Spectra relies on the preview values returned from the external vaults it integrates with. Specifically, [previewDeposit & previewRedeemForIBT function](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L430-L438)

However, there are no checks in the actual `deposit` and `redeem` functions to validate that actual IBT amounts match these preview values.

A malicious ERC4626 vault could exploit this by:

1. Inflating the `previewDeposit` IBT amount returned to Spectra. This would mint more PT than deserved.

2. Deflating the actual IBT amount returned in `deposit`. This leaves room for theft of assets.

Similarly in withdrawals, actual IBT amount transferred out could exceed preview.

1. Attacker deploys a malicious ERC4626 vault that overrides `previewDeposit` to return 2X the normal asset to IBT amount
2. Spectra's `previewDeposit` converts this to double PT shares 
3. Spectra's `deposit` sends 100 DAI to malicious vault
4. Malicious vault should deposit 100 DAI but actually deposits 50 DAI and steals 50 DAI 
5. But full 100 DAI's worth PT was minted in step 2

This allows arbitrage and theft.

## Proof of Concept
The `previewDeposit` and `previewRedeemForIBT` functions rely on external Vault contract responses: [File: src/tokens/PrincipalToken.sol:: previewDeposit and previewRedeemForIBT](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L430-L438)

```solidity
function previewDeposit(uint256 assets) public view override returns (uint256) {
    uint256 ibts = IERC4626(ibt).previewDeposit(assets);
    return _previewDepositIBT(ibts);
}

function previewDepositIBT(uint256 ibts) external view override returns (uint256) {
    return _previewDepositIBT(ibts);
}
```

function previewRedeemForIBT(shares) {
  return convertSharesToIBT(shares)  
}
```

However, actual [deposit](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L171-L198) and [redeemForIBT](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L253-L275) do not validate parity: 

```solidity
function deposit(assets) {
  // No check that actual IBT amount >= previewDeposit amount 
}

function redeemForIBT(shares) {
  // No check that actual IBT amount <= previewRedeemForIBT amount
}
```

This arbitrag
The IBT's transfer and `transferFrom` functions altering balances that could manipulate Spectra's `ibtRate` calculation.
Audit: 2024-02-spectra-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L902
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/YieldToken.sol#L71-L77
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L902-L905
https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L902-L905


# Vulnerability details

## Description
The `ibtRate` is calculated based on the IBT's `totalAssets()`/`totalSupply()`. If an IBT's `transfer` or `transferFrom` functions altered these balances without properly emitting events that Spectra listens for, it could throw off the `ibtRate`.

For example, if an IBT had a transfer function that burned tokens without updating `totalSupply`, transferring tokens could reduce `totalSupply` without reducing `totalAssets`. This would make `ibtRate` artificially high.

The fact that Spectra trusts the IBT to properly update its `totalSupply` when tokens are minted/burned. Specifically, the `ibtRate` calculation relies on: [File: Line 902](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/PrincipalToken.sol#L902)

```solidity
uint256 currentIBTRate = IERC4626(ibt).previewRedeem(ibtUnit).toRay(_assetDecimals);
```
Here, it assumes totalSupply is accurately maintained by the IBT. 

**This is now it could be exploited** if an IBT implemented a malicious transfer function that burns tokens without decrementing `totalSupply`, it could artificially inflate `ibtRate`. 

For example, consider the following vulnerable transfer function in the IBT: [File: src/tokens/YieldToken.sol::transfer](https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/tokens/YieldToken.sol#L71-L77)

```solidity
function transfer(
    address to,
    uint256 amount

    // BAD: Burns tokens but does not update totalSupply
) public virtual override(IYieldToken, ERC20Upgradeable) returns (bool success) {
    IPrincipalToken(pt).beforeYtTransfer(msg.sender, to);

    // Transfers tokens from msg.sender to to
    return super.transfer(to, amount);
}
```
Now when a user calls this transfer function:
- The user's balance is decreased by `amount` (**token burn**) 
- But `totalSupply` remains the same  
- Since `totalAssets` remains unchanged, this increases `ibtRate`

This means the `ibtRate` no longer accurately represents the yield. Users could exploit this to manipulate rates in their favor.

> This could realistically happen if Spectra integrates with an IBT that inaccurately updates `totalSupply`. It's likely given Spectra allows any ERC4626 vault. An unsuspecting vault could easily have this flaw.

## Impact
Manipulation of `ibtRate` directly affects user yield calculations. Attackers could inflate their yield entitlements and
Use of selector can be missleading
Audit: 2024-01-renft-findings
Severity: HIGH

# Lines of code

https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Guard.sol#L195


# Vulnerability details

## Impact
multicall and other contracts can be used to bypass the selector restriction put in place.

## Proof of Concept
https://postimg.cc/fVtDHy1b
https://postimg.cc/XZDVxFYX

## Tools Used
manual review

## Recommended Mitigation Steps
safe guards can be used to track state changes, however using them to track what selectors pass by the safe's transactions can give a false since of security since multicall can be used to grant access to 'approve' or 'setApprovalForAll' function without triggering the guard check


## Assessed type

call/delegatecall
Lack of Validation Parameters in _calculatePaymentProRata Function
Audit: 2024-01-renft-findings
Severity: HIGH

# Lines of code

https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/modules/PaymentEscrow.sol#L159


# Vulnerability details

## Impact
if it  supply arbitrary values for amount, elapsedTime, and totalTime, leading to incorrect calculations in the payment pro-rata distribution. This could result in substantial financial losses for both renters and lenders,
## Proof of Concept
 In the _calculatePaymentProRata function of  contract. The function currently lacks essential validation parameters, such as ensuring the validity of the amount, elapsedTime, and totalTime inputs. This missing validation may allow arbitrary values to be used in the calculation, 

https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/modules/PaymentEscrow.sol#L159C4-L179C6

   function _settlePaymentProRata(
        address token,
        uint256 amount,
        address lender,
        address renter,
        uint256 elapsedTime,
        uint256 totalTime
    ) internal {
        // Calculate the pro-rata payment for renter and lender.
        (uint256 renterAmount, uint256 lenderAmount) = _calculatePaymentProRata(
            amount,
            elapsedTime,
            totalTime
        );


        // Send the lender portion of the payment.
        _safeTransfer(token, lender, lenderAmount);


        // Send the renter portion of the payment.
        _safeTransfer(token, renter, renterAmount);
    } 
## Tools Used

## Recommended Mitigation Steps

 parameter validation checks within the _calculatePaymentProRata function. Ensure that the provided input values are within acceptable ranges and adhere to the expected constraints


## Assessed type

Invalid Validation
Renter can disable Reclaimer module, locking all rented assets in safe
Audit: 2024-01-renft-findings
Severity: HIGH

# Lines of code

https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/libraries/RentalConstants.sol#L62
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Guard.sol#L255-L267


# Vulnerability details

## Impact
The `Guard.sol` contract in the reNFT protocol is responsible for checking transactions initiated by a rental safe to decide whether they can be allowed or not. One of the functionalities it does allow is the ability to enable and disable whitelisted modules in the safe. From the sponsor:
> the idea is that later on we will work with protocols that want to have a better integration with our rental safes.
> By using whitelisted modules, we could implement custom functionality for that protocol which our users could opt into. 

However, there is a critical issue in the way the `Guard.sol` contract handles the disabling of modules. The `disableModule(address prevModule, address module)` function in a Gnosis Safe is used to disable a module, where `prevModule` is the previous module in the linked list of modules, and `module` is the module to be disabled:
https://github.com/safe-global/safe-contracts/blob/47a3620ed937c780d26ff218b76edaaef658f7e2/contracts/base/ModuleManager.sol#L63-L70
```solidity
    function disableModule(address prevModule, address module) public authorized {
        // Validate module address and check that it corresponds to module index.
        require(module != address(0) && module != SENTINEL_MODULES, "GS101");
        require(modules[prevModule] == module, "GS103");
        modules[prevModule] = modules[module];
        modules[module] = address(0);
        emit DisabledModule(module);
    }
```

The issue is that in the `RentalConstants` contract, the `gnosis_safe_disable_module_offset` is set to `0x24`, which means the `prevModule` parameter will be extracted and checked against the whitelist:
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/libraries/RentalConstants.sol#L62
```solidity
uint256 constant gnosis_safe_disable_module_offset = 0x24;
```
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Guard.sol#L255-L267
```solidity
	} else if (selector == gnosis_safe_disable_module_selector) {
		// Load the extension address from calldata.
		address extension = address(
			uint160(
				uint256(
					_loadValueFromCalldata(data, gnosis_safe_disable_module_offset)
				)
			)
		);

		// Check if the extension is whitelisted.
		_revertNonWhitelistedExtension(extension);
```
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Guard.sol#L108-L117
```solidity
    function _loadValueFromCalldata(
        bytes memory data,
        uint256 offset
    ) private pure returns (bytes32 value) {
        // Load the `uint256` from calldata at the offset.
        assembly {
            value := mload(add(d
Guard can be completely bypassed via `setFallbackHandler()`
Audit: 2024-01-renft-findings
Severity: HIGH

# Lines of code

https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/policies/Guard.sol#L203-L291
https://github.com/safe-global/safe-contracts/blob/47a3620ed937c780d26ff218b76edaaef658f7e2/contracts/Safe.sol#L41
https://github.com/safe-global/safe-contracts/blob/47a3620ed937c780d26ff218b76edaaef658f7e2/contracts/base/FallbackManager.sol#L50-L81


# Vulnerability details

## Impact
The `Guard` policy acts as a Gnosis Safe guard designed to protect rented assets from unauthorized transfers. It does this by checking the target and function selector of each transaction initiated by a rental safe and reverting transactions that could potentially lead to unauthorized transfers. 

However, there is a vulnerability in the `Guard` contract that allows an attacker to bypass these checks and transfer rented NFTs to any address. This is possible because the `Guard` contract does not block the `setFallbackHandler()` function of the Gnosis Safe:
https://github.com/safe-global/safe-contracts/blob/47a3620ed937c780d26ff218b76edaaef658f7e2/contracts/base/FallbackManager.sol#L50-L53
```solidity
function setFallbackHandler(address handler) public authorized {
	internalSetFallbackHandler(handler);
	emit ChangedFallbackHandler(handler);
}
```

The `setFallbackHandler()` function allows the owner of a Gnosis Safe to specify a contract that will receive all calls that do not match any function in the Safe contract. If an attacker sets the fallback handler of a rental safe to the contract of a rented ERC721 or ERC1155, they can then call any function of the token contract directly through the fallback function. The `Guard` contract will not block this transaction because the call is forwarded directly to the fallback handler:
https://github.com/safe-global/safe-contracts/blob/47a3620ed937c780d26ff218b76edaaef658f7e2/contracts/base/FallbackManager.sol#L61-L81
```solidity
fallback() external {
	bytes32 slot = FALLBACK_HANDLER_STORAGE_SLOT;
	// solhint-disable-next-line no-inline-assembly
	assembly {
		let handler := sload(slot)
		if iszero(handler) {
			return(0, 0)
		}
		calldatacopy(0, 0, calldatasize())
		// The msg.sender address is shifted to the left by 12 bytes to remove the padding
		// Then the address without padding is stored right after the calldata
		mstore(calldatasize(), shl(96, caller()))
		// Add 20 bytes for the address appended add the end
		let success := call(gas(), handler, 0, 0, add(calldatasize(), 20), 0, 0)
		returndatacopy(0, 0, returndatasize())
		if iszero(success) {
			revert(0, returndatasize())
		}
		return(0, returndatasize())
	}
}
```

This vulnerability allows an attacker to transfer rented NFTs to any address, effectively stealing the token from the rental safe.

## Proof of Concept
We can validate the vulnerability through an additional test case for the `CheckTransaction.t.sol` test file. This test case will simulate the exploit scenario and confirm the issue by performing the following actions:
Front-Running Vulnerability in Deposit 
Audit: 2024-01-renft-findings
Severity: HIGH

# Lines of code

https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/modules/PaymentEscrow.sol#L292


# Vulnerability details

## Impact
there _decreaseDeposit potential front-running vulnerability in the deposit management functions of our smart contract. Specifically, the `_decreaseDeposit` function may be susceptible to front-running attacks, where an attacker monitors the mempool for transactions decreasing the deposit and exploits the situation by executing their own transaction. and inflate the profit
## Proof of Concept
https://github.com/re-nft/smart-contracts/blob/3ddd32455a849c3c6dc3c3aad7a33a6c9b44c291/src/modules/PaymentEscrow.sol#L292C4-L295C6
 function _decreaseDeposit(address token, uint256 amount) internal {
        // Directly decrease the synced balance.
        balanceOf[token] -= amount;
    }

## Tools Used

## Recommended Mitigation Steps


## Assessed type

MEV