Farseen0/scar-pairs huggingface dataset:
HIGH severity: Thunder Brawl — claimReward() - rewards are being drained due to a reentrancy bug.. The vulnerable code snippet demonstrates a reentrancy attack scenario. The `sendReward()` function within the Thunder Brawl contract calls the `reward()` function of another contract (`thunderbrawlRoulette`). This call allows an attacker to execute malicious code within their own contract before the

Vulnerable code:
function claimReward(
        uint256 _ID,
        address payable _player,
        uint256 _amount,
        bool _rewardStatus,
        uint256 _x,
        string memory name,
        address _add
    ) external {
        require(gameMode);
        bool checkValidity = guess(_x, name, _add);

        if (checkValidity == true) {
            if (winners[_ID][_player] == _amount) {
                _player.transfer(_amount * 2);
                if (_rewardStatus == true) {
                    sendReward(); //vulnerable point
                }
                delete winners[_ID][_player];
            } else {
                if (_rewardStatus == true) {
                    sendRewardDys();
                }
            }
            rewardStatus = false;
        }
    }

function sendReward() public {
        thunderbrawlRoulette.reward(msg.sender, 1);
    }

...

function reward(address to,uint256 _mintAmount) external {
        uint256 supply = totalSupply();
        uint256 rewardSupply = rewardTotal;
        require(rewardSupply <= rewardSize,""");
        for (uint256 i = 1; i <= _mintAmount; i++) {          
          _safeMint(to, supply + i); 
          rewardTotal++;         
        }
  }
/**
     * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
     * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
     */
    function _safeMint(
        address to,
        uint256 tokenId,
        bytes memory data
    ) internal virtual {
        _mint(to, tokenId);
        require(
            _checkOnERC721Received(address(0), to, tokenId, data), //callback 
            "ERC721: transfer to non ERC721Receiver implementer"
        );
    }

Vulnerability type: ERC721, Reentrancy
HIGH severity: Grim Finance — Insufficient validation & Reentrancy. Due to token is controllable, the attacker can send fake tokens to the GrimBoostVault through the fake contract created by attacker. Then successful to mint protocol token.. Due to token is controllable, the attacker can send fake tokens to the GrimBoostVault through the fake contract created by attacker. Then successful to mint protocol token.

Vulnerable code:
function depositFor(address token, uint _amount,address user ) public {

        uint256 _pool = balance();
        IERC20(token).safeTransferFrom(msg.sender, address(this), _amount); //vulnerable point
        earn();
        uint256 _after = balance();
        _amount = _after.sub(_pool); // Additional check for deflationary tokens
        uint256 shares = 0;
        if (totalSupply() == 0) {
            shares = _amount;
        } else {
            shares = (_amount.mul(totalSupply())).div(_pool);
        }
        _mint(user, shares);
    }

Vulnerability type: Insufficient validation, Reentrancy, Yield
HIGH severity: yearnFInance — Set bZxUSDC address instead of bZxUSDT. It seems like the iearn USDT token (yUSDT) has been broken since deploy, which was checks notes over 1000 days ago. It was misconfigured to use the Fulcrum iUSDC token instead of the Fulcrum iUSDT token.. https://twitter.com/cmichelio/status/1646422861219807233 https://twitter.com/BeosinAlert/status/1646481687445114881

Vulnerable code:
constructor() public ERC20Detailed("iearn USDT", "yUSDT", 6) {
	fulcrum = address(0xF013406A0B1d544238083DF0B93ad0d2cBE0f65f);  // misconfigured
}

Vulnerability type: Misconfiguration
HIGH severity: HedgeyFinance — Incorrect logic, After the user cancels the campaign, the contract withdraws all the locked tokens to the campaign manager. The vulnerability lies in the failure to revoke the allowance for the campaign manager.. https://x.com/Cube3AI/status/1781294512716820918 https://medium.com/@CUBE3AI/hedgey-finance-hack-detected-by-cube3-ai-minutes-before-exploit-1f500e7052d4

Vulnerable code:
function createLockedCampaign(
    bytes16 id,
    Campaign memory campaign,
    ClaimLockup memory claimLockup,
    Donation memory donation
) external nonReentrant {
    require(!usedIds[id], 'in use');
    usedIds[id] = true;
    require(campaign.token != address(0), '0_address');
    require(campaign.manager != address(0), '0_manager');
    require(campaign.amount > 0, '0_amount');
    require(campaign.end > block.timestamp, 'end error');
    require(campaign.tokenLockup != TokenLockup.Unlocked, '!locked');
    require(claimLockup.tokenLocker != address(0), 'invalide locker');
    TransferHelper.transferTokens(campaign.token, msg.sender, address(this), campaign.amount + donation.amount);
    if (donation.amount > 0) {
      if (donation.start > 0) {
        SafeERC20.safeIncreaseAllowance(IERC20(campaign.token), donation.tokenLocker, donation.amount); // <--- vulnerable point
        ILockupPlans(donation.tokenLocker).createPlan(
          donationCollector,
          campaign.token,
          donation.amount,
          donation.start,
          donation.cliff,
          donation.rate,
          donation.period
        );
      } else {
        TransferHelper.withdrawTokens(campaign.token, donationCollector, donation.amount);
      }
      emit TokensDonated(id, donationCollector, campaign.token, donation.amount, donation.tokenLocker);
    }
    claimLockups[id] = claimLockup;
    SafeERC20.safeIncreaseAllowance(IERC20(campaign.token), claimLockup.tokenLocker, campaign.amount);
    campaigns[id] = campaign;
    emit ClaimLockupCreated(id, claimLockup);
    emit CampaignStarted(id, campaign);
}

Vulnerability type: Business Logic Flaw
HIGH severity: LUSD — the loan contract use getAmountsOut to calculate how many lusd should be mint,and the hacker manipulate the BTCB-BSC-USD pool, borrow 1BTC and return 800k BSC-USD,so the loan contract will mint extra lusd. the loan contract use getAmountsOut to calculate how many lusd should be mint,and the hacker manipulate the BTCB-BSC-USD pool, borrow 1BTC and return 800k BSC-USD,so the loan contract will mint extra lusd

Vulnerable code:
function getAmountsOut(uint amountIn, address[] calldata path) external view returns (uint[] memory amounts);

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: Uwerx — The attacker exploited the ability to burn UWERX tokens, decreasing the total supply and raising the token price artificially. They borrowed 20,000 ETH via flash loans, exchanged it for 5,053,637 UWERX tokens, and used the private _transfer() function to burn 1% of transferred tokens. This reduction in supply allowed them to sell UWERX tokens at a higher price, resulting in a profit.. https://twitter.com/deeberiroz/status/1686683788795846657

Vulnerable code:
function _transfer(
        address from,
        address to,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }
        if (to == uniswapPoolAddress) {
            uint256 userTransferAmount = (amount * 97) / 100;
            uint256 marketingAmount = (amount * 2) / 100;
            uint256 burnAmount = amount - userTransferAmount - marketingAmount;

            emit Transfer(from, to, userTransferAmount);
            emit Transfer(from, marketingWalletAddress, marketingAmount);
            _burn(from, burnAmount);

        } else {
            emit Transfer(from, to, amount);
        }
        
        _afterTokenTransfer(from, to, amount);
    }

Vulnerability type: Price Manipulation
HIGH severity: JAY — Reentrancy. The attacker exploits this vulnerability to reenter the JAY contract. Specifically, the attacker first borrows 72.5 ETH for flash loan and uses 22 ETH to buy JAY token. Then he uses another 50.5 ETH to call the buyJay function, passing the fake ERC-721 token. In the transferFrom function of the fake ERC-721 token, the attacker reenters the JAY contract by calling the sell function, selling all the JAY token. As the Ether balance has been increased at the start of the buyJay function, the JAY token price is manipulated. The attacker repeated the procedure twice in a single transaction, with a total profit of 15.32 Ether.. https://twitter.com/BlockSecTeam/status/1608372475225866240

Vulnerable code:
function buyJay(
        address[] calldata erc721TokenAddress,
        uint256[] calldata erc721Ids,
        address[] calldata erc1155TokenAddress,
        uint256[] calldata erc1155Ids,
        uint256[] calldata erc1155Amounts
    ) public payable {
        require(start, "Not started!");
        uint256 total = erc721TokenAddress.length;
        if (total != 0) buyJayWithERC721(erc721TokenAddress, erc721Ids);

        if (erc1155TokenAddress.length != 0)
            total = total.add(
                buyJayWithERC1155(
                    erc1155TokenAddress,
                    erc1155Ids,
                    erc1155Amounts
                )
            );

        if (total >= 100)
            require(
                msg.value >= (total).mul(sellNftFeeEth).div(2),
                "You need to pay ETH more"
            );
        else
            require(
                msg.value >= (total).mul(sellNftFeeEth),
                "You need to pay ETH more"
            );

        _mint(msg.sender, ETHtoJAY(msg.value).mul(97).div(100));

        (bool success, ) = dev.call{value: msg.value.div(34)}("");
        require(success, "ETH Transfer failed.");

        nftsSold += total;

        emit Price(block.timestamp, JAYtoETH(1 * 10**18));
    }

function JAYtoETH(uint256 value) public view returns (uint256) {
        return (value * address(this).balance).div(totalSupply());
    }

Vulnerability type: Insufficient validation, Reentrancy
HIGH severity: DEPUSDT_LEVUSDC — A public function that enabled the attacker to obtain approval as a spender for $DEPUSDT and $LEVUSDC tokens.. https://blog.solidityscan.com/depusdt-and-levusdc-hack-analysis-d27032d8f2cd

Vulnerable code:
function approveToken(address token, address spender, uint _amount) public returns (bool) {
    IERC20(token).safeApprove(spender, _amount);
    return true;
}

Vulnerability type: Access Control
HIGH severity: Palmswap — The root cause is that the price of `$PLP`  is determined by the number of `$USDT` in the Vault contract and the $USDP supply. 
The attacker was able to manipulate the amount of `$USDT` in the Vault by calling the `buyUSDP`function.. https://twitter.com/BlockSecTeam/status/1683680026766737408

Vulnerable code:
function buyUSDP(address _receiver)
external

override

nonReentrant

returns (uint256)

_increaseUsdpAmount(mintAmount);
_increasePoolAmount(tokenAmount);

IUSDP(usdp).mint(_receiver, mintAmount);
emit BuyUSDP(_receiver, tokenAmount, mintAmount, feeBasisPoints);

useSwapPricing = false;
return mintAmount;

function _increasePoolAmount(uint256 _amount) private {

poolAmount += _amount;
uint256 balance = IERC20Upgradeable(collateralToken).balanceOf(
address(this));

_validate(poolAmount <= balance, 40);
emit IncreasePoolAmount(_amount);
} ... function getAumInUsdp(bool maximise) public view override returns (uint256) {
    uint256 aum = getAum(maximise);
    return (aum * (10**USDP_DECIMALS)) / PRICE_PRECISION;
}

IVault _vault = vault;
uint256 collateralTokenPrice = _vault.getMaxPrice(collateralToken);
uint256 minPrice = _vault.getMinPrice(collateralToken);
uint256 collateralDecimals = _vault.tokenDecimals(collateralToken);

uint256 currentAum = (_vault.permanentPoolAmount() * collateralTokenPrice) / (10**collateralDecimals);
// the poolAmount is manipulated via buyUSDP
// lift the price of the PLP

Vulnerability type: Price Manipulation
HIGH severity: CAROLProtocol — The `Carol::sell` function can be re-entered due to the lack of a reentrancy guard, allowing the attacker to swap more CAROL for WETH in each recursive call. The `getTokenLiquidity()` function will then return a disproportionate result, leading to the manipulation of `ethReserved`.. https://x.com/MetaSec_xyz/status/1730496513359647167

Vulnerable code:
function sell(uint256 tokensAmount) external {
    require(userBalance(msg.sender) >= tokensAmount, "Sell: insufficient balance");

    collect(msg.sender);
    Models.User storage user = users;
    path[0] = TOKEN_ADDRESS;
    path[1] = Constants.WRAPPED_ETH;

    CAROLToken(TOKEN_ADDRESS).mint(address(this), tokensAmount);
    CAROLToken(TOKEN_ADDRESS).increaseAllowance(UNISWAP_ROUTER_ADDRESS, tokensAmount);
		
		// Vulnerable Code Section
    uint256[] memory amounts = IUniswapV2Router01(UNISWAP_ROUTER_ADDRESS).swapExactTokensForETH(
      tokensAmount,
      0,
      path,
      msg.sender,
      block.timestamp + 5 minutes
    );
    uint256 ethAmount = amounts[1];
    

    (uint256 ethReserved, ) = getTokenLiquidity();
    uint256 liquidity = ERC20(LP_TOKEN_ADDRESS).totalSupply()
      * ethAmount
      * (Constants.PERCENTS_DIVIDER + PRICE_BALANCER_PERCENT)
      / Constants.PERCENTS_DIVIDER
      / ethReserved;

    ERC20(LP_TOKEN_ADDRESS).approve(
      UNISWAP_ROUTER_ADDRESS,
      liquidity
    );

    (, uint256 amountETH) = IUniswapV2Router01(UNISWAP_ROUTER_ADDRESS).removeLiquidityETH(
      TOKEN_ADDRESS,
      liquidity, 
      0, 
      0, 
      address(this),
      block.timestamp + 5 minutes
    );

    path[0] = Constants.WRAPPED_ETH;
    path[1] = TOKEN_ADDRESS;
    amounts = IUniswapV2Router01(UNISWAP_ROUTER_ADDRESS).swapExactETHForTokens {value: amountETH} (
      0,
      path,
      address(this),
      block.timestamp + 5 minutes
    );

    emit Events.Sell(
      msg.sender, tokensAmount, ethAmount, block.timestamp
    );
  }

Vulnerability type: Price Manipulation, Reentrancy
HIGH severity: BabySwap — Insufficient validation. Attacker created fake factory contract to get real reward tokens.nVulnerable code snippet:
https://bscscan.com/address/0x5c9f1A9CeD41cCC5DcecDa5AFC317b72f1e49636#code#F4#L236
https://bscscan.com/address/0x8317c460c22a9958c27b4b6403b98d2ef4e2ad32#code#F14#L89

Vulnerable code:
function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] memory path,
        address[] memory factories,
        uint[] memory fees,
        address to,
        uint deadline
    ) external virtual override ensure(deadline) returns (uint[] memory amounts) {
        amounts = BabyLibrarySmartRouter.getAggregationAmountsOut(factories, fees, amountIn, path);
        require(amounts[amounts.length - 1] >= amountOutMin, 'BabyRouter: INSUFFICIENT_OUTPUT_AMOUNT');
        amounts[0] = routerFee(factories[0], msg.sender, path[0], amounts[0]);
        TransferHelper.safeTransferFrom(
            path[0], msg.sender, BabyLibrarySmartRouter.pairFor(factories[0], path[0], path[1]), amounts[0]
        );
        _swap(amounts, path, factories, to); **//vulnerable point -** Insufficient validation
    } ... // swapMining only router
    function swap(address account, address input, address output, uint256 amount) public onlyRouter returns (bool) {
        require(account != address(0), "SwapMining: taker swap account is the zero address");
        require(input != address(0), "SwapMining: taker swap input is the zero address");
        require(output != address(0), "SwapMining: taker swap output is the zero address");

        if (poolLength() <= 0) {
            return false;
        }

        if (!isWhitelist(input) || !isWhitelist(output)) {
            return false;
        }

        address pair = BabyLibrary.pairFor(address(factory), input, output);
        PoolInfo storage pool = poolInfo[pairOfPid[pair]];
        // If it does not exist or the allocPoint is 0 then return
        if (pool.pair != pair || pool.allocPoint <= 0) {
            return false;
        }

        uint256 quantity = getQuantity(output, amount, targetToken);
        if (quantity <= 0) {
            return false;
        }

        mint(pairOfPid[pair]);

        pool.quantity = pool.quantity.add(quantity);
        pool.totalQuantity = pool.totalQuantity.add(quantity);
        UserInfo storage user = userInfo[pairOfPid[pair]][account];
        user.quantity = user.quantity.add(quantity);
        user.blockNumber = block.number;
        return true;
    }

Vulnerability type: Dex/AMM
HIGH severity: Platypus — The `MasterPlatypusV4::emergencyWithdraw` function checks solvency before updating LP tokens, allowing users to withdraw funds even if they are used as collateral for a debt. In contrast, the `MasterPlatypusV4::withdraw` function checks solvency after updating the LP tokens, preventing this issue. To fix the `emergencyWithdraw` function, the solvency check should be reordered to occur after setting the user's amount to 0 or use the debt amount from `PlatypusTreasure::isSolvent` to ensure no active debt.

The attack originated from incorrect integration of `MasterPlatypusV4` with `PlatypusTreasure`, where the solvency check order allowed collateral to be withdrawn with active debt, creating 'bad debt' and resulting in the exchange of USP tokens for stable coins.. https://twitter.com/BlockSecTeam/status/1712445197538468298 https://twitter.com/peckshield/status/1712354198246035562

Vulnerable code:
// @notice Withdraw without caring about rewards. EMERGENCY ONLY.

/// @param _pid the pool id
function emergencyWithdraw(uint256 _pid) public nonReentrant {
    PoolInfo storage pool = poolInfo[_pid];
    if (address(platypusTreasure) != address(0)) {
        (bool isSolvent, ) = platypusTreasure.isSolvent(msg.sender, address(poolInfo[_pid].lpToken), true);
        require(isSolvent, 'remaining amount exceeds collateral factor');
    }

    // reset rewarder before we update lpSupply and sumOfFactors
    IBoostedMultiRewarder rewarder = pool.rewarder;
    if (address(rewarder) != address(0)) {
        rewarder.onPtpReward(msg.sender, user.amount, 0, user.factor, 0);
    }

    // SafeERC20 is not needed as Asset will revert if transfer fails
    pool.lpToken.transfer(address(msg.sender), user.amount);

    // update non-dialuting factor returns all the users deposit, even they have debt
    pool.sumOfFactors -= user.factor;
    user.amount = 0;
    user.factor = 0;
    user.rewardDebt = 0;

    emit EmergencyWithdraw(msg.sender, _pid, user.amount);
}

Vulnerability type: Business Logic Flaw, Flashloans
HIGH severity: Quixotic — fillSellOrder function only check seller signature.. Quixotic only check buyers signature only.

Vulnerable code:
/*
    * @dev External trade function. This accepts the details of the sell order and signed sell
    * order (the signature) as a meta-transaction.
    *
    * Emits a {SellOrderFilled} event via `_fillSellOrder`.
    */
    function fillSellOrder(
        address payable seller,
        address contractAddress,
        uint256 tokenId,
        uint256 startTime,
        uint256 expiration,
        uint256 price,
        uint256 quantity,
        uint256 createdAtBlockNumber,
        address paymentERC20,
        bytes memory signature,
        address payable buyer
    ) external payable whenNotPaused nonReentrant {
        // If the payment ERC20 is the zero address, we check that enough native ETH has been sent
        // with the transaction. Otherwise, we use the supplied ERC20 payment token.
        if (paymentERC20 == address(0)) {
            require(msg.value >= price, "Transaction doesn't have the required ETH amount.");
        } else {
            _checkValidERC20Payment(buyer, price, paymentERC20);
        }

        SellOrder memory sellOrder = SellOrder(
            seller,
            contractAddress,
            tokenId,
            startTime,
            expiration,
            price,
            quantity,
            createdAtBlockNumber,
            paymentERC20
        );

        /* Make sure the order is not cancelled */
        require(
            cancellationRegistry.getSellOrderCancellationBlockNumber(seller, contractAddress, tokenId) < createdAtBlockNumber,
            "This order has been cancelled."
        );

        /* Check signature */
        require(_validateSellerSignature(sellOrder, signature), "Signature is not valid for SellOrder."); //vulnerable point

        // Check has started
        require((block.timestamp > startTime), "SellOrder start time is in the future.");

        // Check not expired
        require((block.timestamp < expiration), "This sell order has expired.");

        _fillSellOrder(sellOrder, buyer);
    }

Vulnerability type: Insufficient validation
HIGH severity: Allbridge — QuillAudits: The root cause of the issue was a logic flaw in the withdraw function. This flaw allowed for manipulation of the swap price of the pool. The exploiter acted as a liquidity provider and swapper, enabling them to manipulate the price and drain the funds from the pool.. https://twitter.com/peckshield/status/1642356701100916736 https://twitter.com/BeosinAlert/status/1642372700726505473 https://medium.com/coinmonks/decoding-allbridge-570k-flash-loan-exploit-quillaudits-8da8dccd729d

Vulnerable code:
// Subtract X and Y for that amount, calculate current price and withdraw the token to the user according to the price
    function withdraw(uint256 amountLp) external {
        uint256 totalLpAmount_ = totalLpAmount; // Gas optimization

        _withdrawLp(msg.sender, amountLp);

        // Calculate actual and virtual tokens using burned LP amount share
        // Swap the difference, get total amount to transfer/burn
        uint256 amountSP = _preWithdrawSwap(
            tokenBalance * amountLp / totalLpAmount_, 
            vUsdBalance * amountLp / totalLpAmount_
        );

        // Always equal amounts removed from actual and virtual tokens
        tokenBalance -= amountSP;
        vUsdBalance -= amountSP;
        
        // Update D and transfer tokens to the sender
        _updateD();
        token.safeTransfer(msg.sender, fromSystemPrecision(amountSP));
    }

Vulnerability type: Business Logic Flaw, Flashloans, Price Manipulation
HIGH severity: BDEX — The underlying issue stems from the fact that the `convertDustToEarned` function within the `BvaultsStrategy` contract lacks price checks. This deficiency becomes particularly problematic for trading pairs with low liquidity, as they are more susceptible to experiencing significant price changes due to variations in trading volume.. https://twitter.com/BeosinAlert/status/1588579143830343683

Vulnerable code:
function convertDustToEarned() public whenNotPaused {
        require(isAutoComp, "!isAutoComp");

        // Converts dust tokens into earned tokens, which will be reinvested on the next earn().

        // Converts token0 dust (if any) to earned tokens
        uint256 _token0Amt = IERC20(token0Address).balanceOf(address(this));
        if (token0Address != earnedAddress && _token0Amt > 0) {
            _vswapSwapToken(token0Address, earnedAddress, _token0Amt);
        }

        // Converts token1 dust (if any) to earned tokens
        uint256 _token1Amt = IERC20(token1Address).balanceOf(address(this));
        if (token1Address != earnedAddress && _token1Amt > 0) {
            _vswapSwapToken(token1Address, earnedAddress, _token1Amt);
        }
    }

Vulnerability type: Price Manipulation