xanoutas/solidity-security-findings huggingface dataset:
[ADD-02] Mitigation Error - `toEthSignedMessageHash()` is not in ECDSA.sol
Audit: 2024-04-ai-arena-mitigation-findings
Severity: HIGH

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/Verification.sol#L20


# Vulnerability details

## Impact
`Verification.verify()` reverts. This breaks `AAMintPass.claimMintPass()`, `FighterFarm.claimFighters()` and `FighterFarm.redeemMintPass()`.

## Proof of Concept
[Verification.sol#L20](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/Verification.sol#L20):
```solidity
bytes32 ethSignedMessageHash = messageHash.toEthSignedMessageHash();
```
will revert because [`toEthSignedMessageHash()` is located in MessageHashUtils.sol](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/11dc5e3809ebe07d5405fe524385cbe4f890a08b/contracts/utils/cryptography/MessageHashUtils.sol#L30).

This breaks [`AAMintPass.claimMintPass()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/AAMintPass.sol#L125), [`FighterFarm.claimFighters()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L233) and [`FighterFarm.redeemMintPass()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L289), which call `Verification.verify()`.

## Recommended Mitigation Steps
```diff
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
+ import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";

...

- bytes32 ethSignedMessageHash = messageHash.toEthSignedMessageHash();
+ bytes32 ethSignedMessageHash = MessageHashUtils.toEthSignedMessageHash(messageHash);
```


## Assessed type

Library
ADD-04 Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: HIGH

# Lines of code




# Vulnerability details

Mitigation of ADD-04: 4/13 mitigated, High unmitigated

## Mitigated issues
[#1490](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1490)

## Mitigation review
Only [L-0], [L-5], [L-6] and [L-10] are mitigated.
[L-8] is a High severity issue that has not been mitigated.
Note that [N-0] is similar to M-02 and unmitigated.

[L-0] [Fixed](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L277). But consider comparing all to `mintpassIdsToBurn.length`, instead of in a chain, for improved readability.
[L-1] [No mitigation attempt](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L544-L551).
[L-2] [No mitigation attempt](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/GameItems.sol#L229-L230).
[L-3] [No mitigation attempt](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L127-L131).
[L-4] [No mitigation attempt](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L150-L154).
[L-5] [Fixed](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/Neuron.sol#L182).
[L-6] [Fixed](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/RankedBattle.sol#L267).
[L-7] [No mitigation attempt](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/RankedBattle.sol#L337). (Issue is of dubious validity.)
[L-8] [Not mitigated](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/RankedBattle.sol#L572-L574). Note that this was [upgraded to High](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/2078#issue-2196304007).
[L-9] No mitigation attempted.
[L-10] This M-04, which is mitigated (see separate review).
[L-11] No mitigation attempt. The issue is of dubious validity, but do consider whether `modelHash` should not be `bytes32` rather than `string`.
[N-0] No mitigation attempt. Note that this is similar to M-02.
[N-1] [No mitigation attempt](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L52).
Upgraded Q -> 2 from #39 [1713839723115]
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

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

 Medium issue 2
https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/RankedBattle.sol#L206-L210
Staking and unstaking is controlled in unison. If staking is possible during the battles, the only way to halt staking it is therefore to also halt unstaking. Users may thus stake during the battles and then suddenly not be able to unstake. It seems that if it was possible to stake during the battles it should always be possible to unstake again.
Contrast this with staking and unstaking outside of battles where users can be expected to make up their minds about how much they want to stake before the battles start, and then be committed to this stake (i.e. allowedStakingDuringRanked remains false).
Being allowed to stake during battles should be interpreted as an added opportunity for the user, with an added risk. The opportunity should not be possible to revoke without also allowing the user to withdraw from the added risk.

Consider not allowing a true allowedStakingDuringRanked be set to false while rankedOpen == true. This way the admin's decision to allow staking during battles will always allow users to unstake until the end of the battles.
Capped loss but huge win exploit
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/RankedBattle.sol#L514-L541


# Vulnerability details

I would like to take this opportunity to bring attention to the issue reported in [#1967](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1967), [#729](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/729), and [#457](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/457), whose severity I believe was overlooked.

**Recap of issue**
The issue was that losses are capped by first having to lose all points and only then one risks putting stake at risk. A specific significant exploit of this is that by staking huge on a fighter with at least one point, then in the next battle one can win huge but risks only dust.

**Objections**
Some objections were made to diminish the degree to which this exploit is profitable: that the attacker cannot guarantee that he can unstake immediately after his huge win, that it is not profitable since it can only be done once per round, and that the staking factor is only the square root of the staked amount.

While all of these present complications for the exploit, the degree to which they do so is severely overestimated.

**Example**
I will show a more detailed deduction below, which concludes with a few examples, in one of which, using reasonable and far from optimized values, this exploit gives the attacker an expected profit of $100$, with a $0.06\\%$ risk of a loss (which then on average is $-14.95$) whereas the usual player's expectation is $0$ with a standard profit/loss of $\pm 71$. This is a significant advantage which warrants this issue being considered of High severity.

**Intuitive rebuttal - square root of staked amount**
That the staking factor is only the square root of the amount staked increases the amount of NRN required. It turns out that the attacker should ideally stake many thousands times more than he would without the exploit. It it still significantly profitable at lower multiples, however. In the example above the attacker only stakes $100$ times as much NRN. Note that this is also for an amount of time much shorter than a round, which means that he can either take out short term loans or cycle his total amount over several fighters, each one for one exploit per round.

**Intuitive rebuttal - only once per round**
The objection that it can only be done once per round overestimates the standard profit from a round. Since matches are made mostly between approximate equals, the expected difference between the number of wins and losses is $0$, and even over as many as $1000$ matches in a round the standard difference is only $16$. That means we only need something like a $16$ times greater advantage (not $1000$) to make the exploit highly significant.

**Intuitive rebuttal - cannot immediately unstake**
It is true that the attacker risks having to lose several times in a row befo
Players can exploit `mintFromMergingPool` dna calculation to mint rare fighter
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L349-L373


# Vulnerability details

# Players can exploit `mintFromMergingPool` dna calculation to mint rare fighter

## Impact
This issue is strongly related to [issue #1017 - Users can get benefited from DNA pseudorandomly calculation](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/1017).
It describes 4 impacts:
1. DNA malipulation in [FighterFarm.reRoll()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L379). It was mitigated in [#16](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/16/commits/255e72b14f124f643003f0cde8eaacaec9ed42e9).
2. DNA manipulation in [FighterFarm.mintFromMergingPool()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L313)
3. DNA malipulation in [FighterFarm.redeemMintPass()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L233). It was mitigated in [#10](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/10/commits/370b0a02d99d7ade4bd04b9c9b784f56b478e841).
4. DNA malipulation in [FighterFarm.claimFighters()](https://github.com/code-423n4/2024-02-ai-arena/blob/main/src/FighterFarm.sol#L191). It was mitigated in [#11](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/11/commits/03d35bd8522ae07fc84474c32978bd58fa20ecb8).

We want to focus on 2. In [issue #1017] is reported:

```
In this case, the DNA is computed by the msg.sender (in this case will always be 
the _mergingPoolAddress so it is not manipulable) and the number of existing fighters.

In this function a user can not manipulate the output hash, however, he can compute the hash for the upcoming fighters, 
because when a new fighter will be created, the fighters.length will change along with the output hash. As a result, 
a user can claim the MergingPool reward to mint and NFT when the output hash will be benefitial for him.
```

So, before mitigation, `a user can not manipulate the output hash`, but `can claim the MergingPool reward to mint and NFT when the output hash will be benefitial for him`.

Attempted mitigation was made in [#3](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/pull/3/files):

```
@@ -321,7 +321,7 @@ contract FighterFarm is ERC721, ERC721Enumerable {
        require(msg.sender == _mergingPoolAddress);
        _createNewFighter(
            to, 
-           uint256(keccak256(abi.encode(msg.sender, fighters.length))), 
+           uint256(keccak256(abi.encode(to, fighters.length))), 
            modelHash, 
            modelType,
            0,
```

We think that this mitigation doesn't solve the issue. Furthermore, it introduces a new vulnerability. Now,
the user can `manipulate the output hash`, because it depends on the `to` address, which can be manipulated by
the user.

## Proof of Concept
The PoC of this issue is similar to the ones in [#53](
[M-05/#578] Mitigation error: user influence on DNA via `to`
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L366


# Vulnerability details

## [M-05/#578] Mitigation error - introduction of issue 2. in `mintFromMergingPool()`
This is not really an error from the mitigation of M-05, but from the mitigation of [#578](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/578), which was a quite distinct (low severity) issue.

## Impact
The user can transfer his token to an address generated by brute force to get a DNA set in `mintFromMergingPool()` such that it mints a fighter with better, or even optimal attributes.
The impact is parallel to the one on `reRoll()` and `claimFighters()` (issue 2. in my mitigation review of M-05), but now impacting `mintFromMergingPool()`.

## Proof of Concept
In the mitigation of #578, the DNA in `mintFromMergingPool()` was changed from `uint256(keccak256(abi.encode(msg.sender, fighters.length)))` to [`uint256(keccak256(abi.encode(to, fighters.length)))`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L366). `to` is [set to `msg.sender` from `MergingPool.claimRewards()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L163). This is checked to be a winner, which is [set by the admin in `pickWinners()` as the owner of the token](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L128).

To change the address the user has to unstake (so transfers are allowed) and transfer his token to the new address before the admin calls `pickWinners()`. This can be done preemptively (if frontrunning is infeasible), simply predicting he may win, and in that case get the desired DNA.

Another complication is that `fighters.length` also determines the DNA. It is not necessary at all that this will change in between his fighter transfer and the admin's call to `pickWinners()`, even if the user cannot frontrun the admin. And even if it does change, the user can with near certainty constrain an estimate to within a few values. He can then optimize his new address with all these values taken into account. As long as they are few he can still ensure a good, or even optimal DNA. (He just needs to optimize over a random tuple instead of a random scalar.)

## Recommended Mitigation Steps
Simply removing `to`, i.e. set DNA to `uint256(keccak256(abi.encode(fighters.length)))`, precludes the user from influencing the DNA to the extent described here. But then he may still wait for a better `fighters.length` (issue 3. in my mitigation review of M-05), which will also enable him to know in advance all the DNAs (like in issue 4. in my mitigation review of M-05).
Adding `blockhash(block.number - 1)` mitigates this up to the issue actually reported in M-05, i.e. that the user can retr
Element and weight correlation when `numElements` is multiple of 31
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/FighterFarm.sol#L516-L517


# Vulnerability details



## Impact
When `numElements` is a multiple of 31 the DNA only generates 1/31 of all intended combinations of `element` and `weight`.

## Proof of Concept
`numElements` maps to a uint8, i.e up to 255. 
In `FighterFarm._createFighterBase()` `element` and `weight` are set as
```solidity
uint256 element = dna % numElements[generation[fighterType]];
uint256 weight = dna % 31 + 65;
```
This means that if `numElements[generation[fighterType]]` is multiple of `31`, say `k*31` then only `k*31` different combinations are possible instead of `k*31 * 31`, since `(n + k*31) % (k*31) == (n + k*31) % 31`.

## Recommended Mitigation Steps
Divide by the first mod to extract multiple smaller random numbers from one big random number.
```solidity
uint256 weight = dna % 31 + 65;
dna = dna/31;
uint256 element = dna % numElements[generation[fighterType]];
```


## Assessed type

Math
The user can select the best out of all rerolls (unmitigated issue 4. grouped under M-05)
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L424


# Vulnerability details



## Impact
The best out of the entire sequence of reroll results can be selected, instead of having to take a chance at each reroll attempt.

## Proof of Concept
The DNA is set in `FighterFarm.reRoll()` as [uint256(keccak256(abi.encode(tokenId, numRerolls[tokenId])))](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L424). This means that the user can calculate the outcomes of all reroll attempts in advance and choose the best one by rerolling until that reroll. This means that it is no longer a reroll but a random sample of fighters offered to the user, from which he can select the best one.

## Recommended Mitigation Steps
The next reroll must not be determined from currently knowable values. This can be achieved by having the admin provide the randomness after a reroll request by the user. This randomness can be in the form of `blockhash(block.number - 1)` set on the admin call.


## Assessed type

Other
User influence on DNA via `fighters.length` in `mintFromMergingPool()` (unmitigated issue 3. grouped under M-05)
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L366


# Vulnerability details



## Impact
The user can wait for an appropriate `fighters.length` to get a better DNA when minting from the merging pool.

## Proof of Concept
A winning user can call `MergingPool.claimRewards()`, which [calls `FighterFarm.mintFromMergingPool()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/MergingPool.sol#L162). Here the DNA is set as [`uint256(keccak256(abi.encode(to, fighters.length)))`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L366). This means that the user can choose to call `claimRewards()` when `fighters.length` is such that the DNA gives better attributes.

## Recommended Mitigation Steps
Note that there is also an issue with using `to` in setting the DNA (the mitigation error from the fix of #578). This mitigation fixes both of these.
Set the DNA as `blockhash(block.number - 1)`. This must be in a call from the admin, otherwise the user could wait for a good blockhash. Then in a second call by the user assign the fighter to the user, either through direct minting to the user, or mint the fighter to an escrow (e.g. FighterFarm itself) and then have the user transfer it to himself in the second call.


## Assessed type

Other
User influence on DNA in `claimFighters()` (unmitigated issue 2. grouped under M-05)
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code

https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L241


# Vulnerability details

## Impact
The user can transfer his token to an address generated by brute force to get a DNA set in `claimFighters()` such that it mints a fighter with optimal attributes.
He may also transfer it to an address with different `nftsClaimed` values to change the DNA.

## Proof of Concept
This issue has been mitigated in `reRoll()` by [replacing `msg.sender` with `tokenId`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L424). But [it has NOT been mitigated in `claimFighters()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/d81beee0df9c5465fe3ae954ce41300a9dd60b7f/src/FighterFarm.sol#L241).

By brute-forcing addresses until `uint256(keccak256(abi.encode(msg.sender, nftsClaimed[msg.sender][0], nftsClaimed[msg.sender][1])))` would return a desirable DNA the user can request a signature for `claimFighters()` by the delegated signer.

## Recommended Mitigation Steps
This specific issue would be mitigated by replacing `msg.sender` by `tokenId` in `claimFighters()` as well. The downside to this solution is that all future DNAs will be entirely predictable. And there is still some room for influencing the DNA by using a different address with other `nftsClaimed` values.
The best way is probably to set the DNA as `blockhash(block.number - 1)`. This must be in a call from the admin, otherwise the user could wait for a good blockhash. Then in a second call by the user assign the fighter to the user, either through direct minting to the user, or mint the fighter to an escrow (e.g. FighterFarm itself) and then have the user transfer it to himself in the second call.


## Assessed type

Other
M-08 Unmitigated
Audit: 2024-04-ai-arena-mitigation-findings
Severity: MEDIUM

# Lines of code




# Vulnerability details

Mitigation of M-08: NOT fully mitigated

## Mitigated issue
[M-08: Burner role can not be revoked](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/47)

The issues were that the burner role in GameItems.sol, and the staker role in FighterFarm.sol (see duplicate [#710](https://github.com/code-423n4/2024-02-ai-arena-findings/issues/710)) cannot be revoked.

## Mitigation review - only case of burner role fixed
`setAllowedBurningAddresses()` in GameItems.sol has been replaced by an [`adjustBurningAccess()`](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/GameItems.sol#L194-L197).

The staker role in FighterFarm.sol still can only be [added](https://github.com/ArenaX-Labs/2024-02-ai-arena-mitigation/blob/1192a55963c92fb4bd9ca8e0453c96af09731235/src/FighterFarm.sol#L151).

### Recommended mitigation steps
Similarly implement an `adjustStakerAccess()` instead for the staker role in FighterFarm.sol.