Farseen0/scar-pairs huggingface dataset:
HIGH severity: Jimbo — This attack exploited a vulnerability in the JimboController contract, which allows anyone to use the shift() function to make the contract execute liquidity removal and addition operations. The shift() function takes the funds of the contract to add liquidity, resulting in all the WETH of the JimboController contract being added as liquidity.

Since the prices of WETH and JIMBO in the pool are not balanced, when adding liquidity, the required token quantity will be calculated based on the current price, allowing the attacker to obtain more WETH.. https://twitter.com/cryptofishx/status/1662888991446941697 https://twitter.com/yicunhui2/status/1663793958781353985

Vulnerable code:
function shift() public returns (bool) { // vulnerable point
        if (canShift()) {
            // Let the token know the protocol is rebalancing
            jimbo.setIsRebalancing(true);

            // Get the active bin
            uint24 activeBin = pair.getActiveId();

            // Remove all non-floor bin liquidity (max bin -> anchor bin)
            _removeNonFloorLiquidity();

            // Remove all floor bin liquidity
            _removeFloorLiquidity();

            // Count the total JIMBO and ETH in the contract after liquidity removal
            uint256 totalJimboInPool = jimbo.balanceOf(address(this));
            uint256 totalEthInContract = weth.balanceOf(address(this));

            // Floor is based on total eth / circulating supply
            uint256 totalCirculatingJimbo = jimbo.totalSupply() -
                jimbo.balanceOf(address(0)) -
                totalJimboInPool;

            // Calculate the new target floor bin
            uint24 newFloorBin = _calculateNewFloorBin(
                totalEthInContract,
                totalCirculatingJimbo
            );

            // Calculate new anchor bin id
            // Make sure you use the new floor bin and not the stale one
            uint24 newAnchorBin = activeBin - newFloorBin > NUM_ANCHOR_BINS
                ? activeBin - NUM_ANCHOR_BINS
                : activeBin - 1;

            // Set internal bin state
            _setBinState({
                floorBin_: newFloorBin,
                anchorBin_: newAnchorBin, // this is not always true
                triggerBin_: activeBin + NUM_ANCHOR_BINS,
                maxBin_: activeBin + NUM_LIQ_BINS - 1 // decrement because we are adding inclusive of active bin
            });

            // Deploy all the JIMBO liquidity first
            _deployJimboLiquidity();  // vulnerable point

            // Deploy floor bin liquidity with 90% of all ETH in the contract
            _deployFloorLiquidity((weth.balanceOf(address(this)) * 90) / 100); // vulnerable point

            // Use entire remaining weth balance in the contract to deploy anchors
            _deployAnchorLiquidity(weth.balanceOf(address(this))); // vulnerable point

            // Let the token know we are done rebalancing to apply taxes
            jimbo.setIsRebalancing(false);
            return true;
        } else return false;
    }

Vulnerability type: Price Manipulation
HIGH severity: TGBS — Vulnerable `transfer()` function. In `transfer()` function, 0.3% of TGBS tokens of Cake-LP is burned, when `_burnBlock` is less than block number. Hacker called `trasnfer` function many times, manipulated TGBS:WBNB ratio, could drain pancake pair.. https://twitter.com/0xNickLFranklin/status/1765290290083144095 https://twitter.com/Phalcon_xyz/status/1765285257949974747

Vulnerable code:
function transfer(
        address to,
        uint256 amount
    ) public virtual override returns (bool) {
        address owner = msg.sender;
        _transfer(owner, to, amount);
        return true;
    }

Vulnerability type: Rug-Pull(Protocol Side)
HIGH severity: Rubic — Arbitrary External Call. The attacker abused that USDC had been added as a router (by the admin), leading to an arbitrary function call with USDC contract. Then the attacker invoked transferFrom to steal the victim's USDC.. https://twitter.com/BlockSecTeam/status/1606993118901198849 https://twitter.com/peckshield/status/1606937055761952770

Vulnerable code:
function routerCallNative(BaseCrossChainParams calldata _params, bytes calldata _data)
        external
        payable
        nonReentrant
        whenNotPaused
        eventEmitter(_params)
    {
        if (!availableRouters.contains(_params.router)) {
            revert RouterNotAvailable();
        }

        IntegratorFeeInfo memory _info = integratorToFeeInfo[_params.integrator];

        uint256 _amountIn = accrueTokenFees(
            _params.integrator,
            _info,
            accrueFixedCryptoFee(_params.integrator, _info),
            0,
            address(0)
        );

        AddressUpgradeable.functionCallWithValue(_params.router, _data, _amountIn);
    }

Vulnerability type: Arbitrary call, Dex/AMM
HIGH severity: Silo finance — dump utilization ratio by borrowing donated token. https://medium.com/immunefi/silo-finance-logic-error-bugfix-review-35de29bd934a

Vulnerable code:
function calculateCurrentInterestRate(
        Config memory _c,
        uint256 _totalDeposits,
        uint256 _totalBorrowAmount,
        uint256 _interestRateTimestamp,
        uint256 _blockTimestamp
    ) public pure override returns (uint256 rcur) {
        if (_interestRateTimestamp > _blockTimestamp) revert InvalidTimestamps();

        // struct for local vars to avoid "Stack too deep"
        LocalVarsRCur memory _l = LocalVarsRCur(0,0,0,0,0,0,false);

        (,,,_l.overflow) = calculateCompoundInterestRateWithOverflowDetection(
            _c,
            _totalDeposits,
            _totalBorrowAmount,
            _interestRateTimestamp,
            _blockTimestamp
        );

        if (_l.overflow) {
            return 0;
        }

        // There can't be an underflow in the subtraction because of the previous check
        unchecked {
            // T := t1 - t0 # length of time period in seconds
            _l.T = (_blockTimestamp - _interestRateTimestamp).toInt256();
        }

        _l.u = EasyMath.calculateUtilization(DP, _totalDeposits, _totalBorrowAmount).toInt256();
        _l.DP = int256(DP);

        if (_l.u > _c.ucrit) {
            // rp := kcrit *(1 + Tcrit + beta *T)*( u0 - ucrit )
            _l.rp = _c.kcrit * (_l.DP + _c.Tcrit + _c.beta * _l.T) / _l.DP * (_l.u - _c.ucrit) / _l.DP;
        } else {
            // rp := min (0, klow * (u0 - ulow ))
            _l.rp = _min(0, _c.klow * (_l.u - _c.ulow) / _l.DP);
        }

        // rlin := klin * u0 # lower bound between t0 and t1
        _l.rlin = _c.klin * _l.u / _l.DP;
        // ri := max(ri , rlin )
        _l.ri = _max(_c.ri, _l.rlin);
        // ri := max(ri + ki * (u0 - uopt ) * T, rlin )
        _l.ri = _max(_l.ri + _c.ki * (_l.u - _c.uopt) * _l.T / _l.DP, _l.rlin);
        // rcur := max (ri + rp , rlin ) # current per second interest rate
        rcur = (_max(_l.ri + _l.rp, _l.rlin)).toUint256();
        rcur *= 365 days;
    }

Vulnerability type: Donate, Math, Under/Overflow
HIGH severity: Dough Finance — ConnectorDeleverageParaswap contract did not validate flash loan callback data which led to WETH transfer.. https://blog.solidityscan.com/doughfina-hack-analysis-685ed56adb19

Vulnerable code:
function deloopAllCollaterals(bytes[] memory multiTokenSwapData) private {
        FlashloanVars memory flashloanVars;

        for (uint i = 0; i < multiTokenSwapData.length;) {
            // Deloop
            (flashloanVars.srcToken, flashloanVars.destToken, flashloanVars.srcAmount, flashloanVars.destAmount, flashloanVars.paraSwapContract, flashloanVars.tokenTransferProxy, flashloanVars.paraswapCallData) = _getParaswapData(multiTokenSwapData[i]);

            // using ParaSwap
            IERC20(flashloanVars.srcToken).safeIncreaseAllowance(flashloanVars.tokenTransferProxy, flashloanVars.srcAmount);
            (flashloanVars.sent, ) = flashloanVars.paraSwapContract.call(flashloanVars.paraswapCallData); // <-- vulnerable point
            if (!flashloanVars.sent) revert CustomError("ParaSwap deloop failed");

            unchecked { i++; }
        }
    }

Vulnerability type: Insufficient validation
HIGH severity: SellToken03 — StakingRewards contract's Claim() function did not properly validate the input parameters, allowing the attacker to pass a fake token to obtain more rewards.. https://twitter.com/BlockSecTeam/status/1657715018908180480

Vulnerable code:
function claim(address token, address token1) public { // vulnerable point: no token validation

        require(listToken[token]);

        require(users[token][msg.sender].mnu > 0);

        require(block.timestamp > stakedOfTime[token][msg.sender]);

        uint minit = block.timestamp - stakedOfTime[token][msg.sender];

        uint coin;

        for (uint i = 0; i < users[token][msg.sender].mnu; i++) {
            if (stakedOfTimeSum[token][msg.sender][i + 1] > minit && stakedOf[token][msg.sender][i + 1] > 0) {
                uint banOf = stakedOf[token][msg.sender][i + 1] / 100;
                uint send = getTokenPrice(token1, token, banOf) / RATE_DAY;
                coin += minit * send;
                stakedOfTimeSum[token][msg.sender][i + 1] -= minit;
            }
        }

        bool isok = IERC20(token).transfer(msg.sender, coin * 50 / 100);

        require(isok);

        stakedOfTime[token][msg.sender] = block.timestamp;

        updateU(token, msg.sender, coin * 50 / 100);
    }

Vulnerability type: Unchecked User Input
HIGH severity: MetaPoint — Public `approve()`. This contract has a function called approve that grants the caller of the function access to the $META tokens without any restriction.. https://twitter.com/PeckShieldAlert/status/1645980197987192833 https://twitter.com/Phalcon_xyz/status/1645963327502204929

Vulnerable code:
function approve() public payable {
    v0, /* bool */ v1 = address(0x3b5e381130673f794a5cf67fbba48688386bea86).approve(msg.sender, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff).gas(msg.gas);
    require(bool(v0), 0, RETURNDATASIZE()); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    require(v1 == bool(v1));
}

Vulnerability type: Access Control
HIGH severity: SellToken04 — The price in the USDT-SELLC pool was manipulated, and the sendMiner function relied on the price from that pool.. The price in the USDT-SELLC pool was manipulated, and the sendMiner function relied on the price from that pool.

Vulnerable code:
function sendMiner(address token public) { 
    uint memory vid = MyMiner[_msgSender()][token]; 
    address token = sellAddress[vid[0]].pair; 
    uint256 token1 = sellAddress[vid[0]].token1; 
    
    require(value[vid[0]] > 0 && block.timestamp > sellAddress[token][vid[1]].time + DAYTIME); 
    require(rniner[vid[0]][token]); 
    require(block.timestamp > sellAddress[token][vid[1]].time + DAYTIME && sellAddress[token][vid[1]].ds < 366); 
    uint _day = (block.timestamp - sellAddress[token][vid[1]].time) / DAYTIME; 
    require(_day >= 1 && _day < 366); 
    
    uint agk = getBnb(token, token1, sellAddress[token][vid[1]].daybnb) * _day; 
    if (IERC20(token).balanceOf(_msgSender()) >= agk) { 
        IERC20(token).transfer(_msgSender(), agk); 
    } 
    sellAddress[token][vid[1]].ds += agk; 
    sellAddress[token][vid[1]].time += DAYTIME * _day; 
} ... function getBnb(address _tokens, address bnbOrUsdt, uint bnb) public view returns (uint) { 
    if (_tokens == address(0)) return 0; 
    address isBnb; 
    if (bnbOrUsdt == _WBNB) { 
        isBnb = WBNB; 
        address; 
        routePath; 
        routePath[0] = WBNB; 
        routePath[1] = isBnb; 
        routePath[2] = _tokens; 
        return IRouter(_router).getAmountsOut(bnb, routePath)[2]; 
    } 
}

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: Poolz — The attacker called the vulnerable function `CreateMassPools` and triggered an integer overflow vulnerability in the parameter `_StartAmount`.. https://twitter.com/BeosinAlert/status/1635878098452492288

Vulnerable code:
function CreateMassPools(
        address _Token,
        uint64[] calldata _FinishTime,
        uint256[] calldata _StartAmount,
        address[] calldata _Owner
    ) external isGreaterThanZero(_Owner.length) isBelowLimit(_Owner.length) returns(uint256, uint256) {
        require(_Owner.length == _FinishTime.length, "Date Array Invalid");
        require(_Owner.length == _StartAmount.length, "Amount Array Invalid");
        TransferInToken(_Token, msg.sender, getArraySum(_StartAmount)); // vulnerable point
        uint256 firstPoolId = Index;
        for(uint i = 0; i < _Owner.length; i++) {
            CreatePool(_Token, _FinishTime[i], _StartAmount[i], _Owner[i]);
        }
        uint256 lastPoolId = SafeMath.sub(Index, 1);
        return (firstPoolId, lastPoolId);
    }

Vulnerability type: Under/Overflow
HIGH severity: Chainswap — incorrect logic. A bug in the token cross-chain quota code is found. The on-chain swap bridge quota is automatically increased by the signature node, which is intended to be more decentralized without manual control. However, due to a logical flaw in code, this led to an exploit by allowing invalid addresses which weren't whitelisted to automatically increase the amount.. [https://medium.com/wilder-world/important-update-chainswap-hack-cf2153480887]
[https://rekt.news/chainswap-rekt/]

Vulnerable code:
function receive(
    address from,
    uint256 nonce,
    bytes memory signatures
) external payable {
    // ... other code
    require(updateAutoQuota(from, signatures), "Invalid signatures"); // vulnerable point
    // ... other code
}

modifier updateAutoQuota(address signatory) virtual {
    uint quota = _authQuotas[signatory];
    if (_authQuotas[signatory] != quota) {
        _authQuotas[signatory] = quota;
        lastTimeUpdatedQuotaOf[signatory] = now;
    }
    _;
}

Vulnerability type: Bridge, CrossChain, Incorrect logic
HIGH severity: UEarnPool — The design flaw in the reward distribution which allows the final reward exceed the invested amount.. Preparation: The attacker deployed 20 attack contracts and bound each of them sequentially The attacker flashloaned 2.4M BUSD and sent to the last contract(0x21c473f) that was created in the previous step. The account stake all USDT to the UEarnpool. As a result, inviters will receive some BUSD toke

Vulnerable code:
// 1. Reward Calculation in the stake function
function stake(uint256 pid, uint256 amount) external {
    // ... (other code)
    uint256 reward = amount * pool.rewardRate / _feeDivFactor; // Risk: High reward rates could lead to excessive rewards
    uint256 feeAmount = amount * _feeRate / _feeDivFactor;

    _userRecords[account].push(
        Record(pid, amount, feeAmount, reward, block.timestamp, block.timestamp + pool.duration, 0)
    );
    // ... (other code)
}

// 2. Total transfer amount in unStake function
function unStake(uint256 index) external {
    // ... (other code)
    IERC20(_tokenAddress).transfer(account, amount + record.reward - record.feeAmount); // Risk: total transfer could exceed initial stake
    // ... (other code)
}

// 3. Invite Reward Calculation in _addInviteReward function
function _addInviteReward(address account, uint256 amount) private {
    for (uint256 i; i < inviteLength;) {
        invitor = _invitor[account];
        if (address(0) == invitor) {
            break;
        }
        // ... (other code)
        uint256 inviteReward = amount * _inviteFee[i] / _feeDivFactor; // Risk: Accumulation could exceed initial investment
        if (inviteReward > 0) {
            invitorInfo.inviteReward += inviteReward;
            token.transfer(invitor, inviteReward);
        }
        // ... (other code)
    }
}

// 4. Level-Based Rewards in claimTeamReward function
function claimTeamReward(address account) external {
    uint256 level = getUserLevel(account);
    uint256 pendingReward;
    LevelConfig storage levelConfig;
    
    if (level != MAX) {
        for (uint256 i; i <= level;) {
            levelConfig = _levelConfigs[i];
            if (_userInfos[account].levelClaimed[i] == 0) {
                uint256 levelReward;
                if (i == 0) {
                    levelReward = levelConfig.teamAmount * levelConfig.rewardRate / _feeDivFactor; // Risk: High rates could lead to excessive rewards
                } else {
                    levelReward = (levelConfig.teamAmount - _levelConfigs[i - 1].teamAmount) * levelConfig.rewardRate / _feeDivFactor;
                }
                pendingReward += levelReward;
                _userInfos[account].levelClaimed[i] = levelReward; // Store claimed reward
            }
            // ... (other code)
        }
    }
    if (pendingReward > 0) {
        IERC20(_tokenAddress).transfer(account, pendingReward); // Risk: Could result in payouts exceeding original investment
    }
}

Vulnerability type: Business Logic Flaw, Flashloans
HIGH severity: Chainswap — insufficient validation. Attacker only needs to generate a random address and generate the corresponding signature to trick ChainSwap.. insufficient validation. Attacker only needs to generate a random address and generate the corresponding signature to trick ChainSwap.

Vulnerable code:
function receive(uint256 fromChainId, address to, uint256 nonce, uint256 volume, Signature[] memory signatures) virtual external payable {
        _chargeFee();
        require(received[fromChainId][to][nonce] == 0, 'withdrawn already');
        uint N = signatures.length;
        require(N >= Factory(factory).getConfig(_minSignatures_), 'too few signatures');
        for(uint i=0; i<N; i++) {
            for(uint j=0; j<i; j++)
                require(signatures[i].signatory != signatures[j].signatory, 'repetitive signatory');
            bytes32 structHash = keccak256(abi.encode(RECEIVE_TYPEHASH, fromChainId, to, nonce, volume, signatures[i].signatory));
            bytes32 digest = keccak256(abi.encodePacked("\x19\x01", _DOMAIN_SEPARATOR, structHash));
            address signatory = ecrecover(digest, signatures[i].v, signatures[i].r, signatures[i].s);
            require(signatory != address(0), "invalid signature");
            require(signatory == signatures[i].signatory, "unauthorized");
            _decreaseAuthQuota(signatures[i].signatory, volume);
            emit Authorize(fromChainId, to, nonce, volume, signatory);
        }
        received[fromChainId][to][nonce] = volume;
        _receive(to, volume);
        emit Receive(fromChainId, to, nonce, volume);
    }

function authQuotaOf(address signatory) virtual public view returns (uint quota) {
        quota = _authQuotas[signatory]; //vulnerable point, no validation
        uint ratio  = autoQuotaRatio  != 0 ? autoQuotaRatio  : Factory(factory).getConfig(_autoQuotaRatio_);
        uint period = autoQuotaPeriod != 0 ? autoQuotaPeriod : Factory(factory).getConfig(_autoQuotaPeriod_);
        if(ratio == 0 || period == 0 || period == uint(-1))
            return quota;
        uint quotaCap = cap().mul(ratio).div(1e18);
        uint delta = quotaCap.mul(now.sub(lasttimeUpdateQuotaOf[signatory])).div(period);
        return Math.max(quota, Math.min(quotaCap, quota.add(delta)));
    }

Vulnerability type: Bridge, CrossChain, Incorrect logic
HIGH severity: TSURU — Everyone can call this function to get free tokens. No access control. https://x.com/shoucccc/status/1788941548929110416

Vulnerable code:
function onERC1155Received( //vulnerable point
        address,
        address from,
        uint256 id,
        uint256 amount,
        bytes calldata
    ) external override nonReentrant returns (bytes4) {
        require(id == tokenID, "Token ID does not match");
        
        if (msg.sender == address(erc1155Contract)) {
            return this.onERC1155Received.selector;
        }

        _safeMint(from, amount * ERC1155_RATIO); // Adjust minting based on the ERC1155_RATIO
        return this.onERC1155Received.selector;
    }

Vulnerability type: Access Control, Insufficient validation
HIGH severity: BambooIA — When the private updatePool function is invoked in the _transfer function, the resulting token transfer will burn the balance of the $BAMBOO token in the pair, causing a rise in the token price.. Post-mortem : [https://twitter.com/Phalcon_xyz/status/1676220090142916611]

Vulnerable code:
if (!isMarketPair[sender] && sale > 0) updatePool(amount); ... function updatePool(uint256 amount) private {
        if (amount > 10000 && balanceOf(uniswapPair) > amount) {
            uint256 fA = amount / 100;
            _balances[uniswapPair] = _balances[uniswapPair].sub(fA);
            _balances[Factory] = _balances[Factory].add(fA);
            try IUniswapV2Pair(uniswapPair).sync() {} catch {}
        }
    }

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: ChannelsFinance — ExchangeRate manipulation. The root cause is the ExchangeRate manipulation. Once the exchangeRate been controlled, hacker could borrow more than their collateral. The contract uses a old Compund V2 protocols which has a known vulenrability.. https://x.com/AnciliaInc/status/1741353303542501455 https://www.comp.xyz/t/hundred-finance-exploit-and-compound-v2/4266

Vulnerable code:
function exchangeRateStoredInternal() internal view returns (MathError, uint) {
    uint _totalSupply = totalSupply;
    if (_totalSupply == 0) {
        /* 
         * If there are no tokens minted:
         * exchangeRate = initialExchangeRate
         */
        return (MathError.NO_ERROR, initialExchangeRateMantissa);
    } else {
        /* 
         * Otherwise:
         * exchangeRate = (totalCash + totalBorrows - totalReserves) / totalSupply
         */
        uint totalCash = getCashPrior();
        uint cashPlusBorrowsMinusReserves;
        Exp memory exchangeRate;
        MathError mathErr;

        (mathErr, cashPlusBorrowsMinusReserves) = addThenSubUInt(totalCash, totalBorrows, totalReserves);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        (mathErr, exchangeRate) = getExp(cashPlusBorrowsMinusReserves, _totalSupply);
        if (mathErr != MathError.NO_ERROR) {
            return (mathErr, 0);
        }

        return (MathError.NO_ERROR, exchangeRate.mantissa);
    }
}

Vulnerability type: Inflation Attack
HIGH severity: Pandora — By overflowing the users balance, the attacker was able to maliciously gain a large amount of pandora tokens. None

Vulnerable code:
function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal returns (bool) {
        uint256 unit = _getUnit();
        uint256 balanceBeforeSender = balanceOf[from];
        uint256 balanceBeforeReceiver = balanceOf[to];

        _preTransferCheck(from, to);

        balanceOf[from] -= amount;
        balanceOf[to] += amount;

        // Skip burn for certain addresses to save gas
        if (!whitelist[from]) {
            uint256 tokens_to_burn = (balanceBeforeSender / unit) -
                (balanceOf[from] / unit);
            for (uint256 i = 0; i < tokens_to_burn; i++) {
                _burn(from);
            }
        }

        // Skip minting for certain addresses to save gas
        if (!whitelist[to]) {
            uint256 tokens_to_mint = (balanceOf[to] / unit) -
                (balanceBeforeReceiver / unit);
            for (uint256 i = 0; i < tokens_to_mint; i++) {
                _mint(to);
            }
        }

        emit ERC20Transfer(from, to, amount);
        return true;
    }

Vulnerability type: Under/Overflow
HIGH severity: Miner — The attack exploited a double spend vulnerability due to inadequate validation. Specifically, the system did not verify that the sender's address was different from the recipient's, enabling the attacker to repay the loan and send tokens to themselves.. https://twitter.com/Phalcon_xyz/status/1757777340002681326

Vulnerable code:
function _transfer(address from, address to, uint256 value, bool mint) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value, mint);
    }

Vulnerability type: Insufficient validation