Farseen0/scar-pairs huggingface dataset:
HIGH severity: APC — Incorrect price calculation via getReverse. APC price relies on the reserve balances of the corresponding PancakeSwap pair. You dump APC token price by flashloan.. https://twitter.com/BlockSecTeam/status/1598262002010378241

Vulnerable code:
function x207() private {
    v0, v1, v2, v3 = stor_c9_19.getReserves().gas(msg.gas);
    require(v0); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() >= 96);
    require(v1 == v1 & 0xffffffff);
    require(v2 == v2 & 0xffffffff);
    require(v3 == uint32(v3));
    v4, v5 = 0x10ed43c718714eb63d5aa57b78b54704e256024e.FULLEXTENDED(v1 & 0xffffffff, v2 & 0xffffffff).gas(msg.gas);
    require(v4); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() >= 32);
    return v5;
}

function x4c3(uint256 varg0, uint256 varg1, uint256 varg2) private {
    v0 = stor_c9_19 == address(varg2);
    if (stor_c9_19 != address(varg2)) {
        v0 = stor_cb_19 == address(varg2);
    }
    require(v0, Error('inputToken address wrong'));
    v0 = x207();
    if (stor_c9_19 != address(varg2)) {
        if (stor_cb_19 == address(varg2)) {
            x99d(varg0, this, msg.sender, stor_cb_19);
            v4 = _SafeMul(v3, varg0);
            require(v4, Panic(18));
            v5 = SafeMul(99, v4 / v5);
            require(v5, Panic(18));
            emit Swap(msg.sender, stor_cb_19, stor_c9_19, varg0, v5 / 100);
        } else {
            x99d(varg0, this, msg.sender, stor_c9_19);
            v6 = _SafeMul(v5, varg2);
            require(v6, Panic(18));
            v7 = SafeMul(99, v6 / v3);
            require(v7, Panic(18));
            emit Swap(msg.sender, stor_c9_19, stor_cb_19, varg0, v7 / 100);
        }
    }
    return;
} ... function swap(address varg0, address varg1, uint256 varg2) public payable {
    require(msg.data.length - 4 >= 96);
    require(varg0 == varg0);
    require(varg1 == varg1);
    0x4c3(varg2, varg1, varg0);
}

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: uniclyNFT — For the first step, the attacker deployed a malicious contract, swapped 0.5 ETH for 3528 uJENNY tokens, and deposited them to `PointFarm` to accumulate initial rewards. Two days later, the attacker launched the actual attack exploiting two bugs:
1. The deposit function allows a 0 `_amount` for minting new tokens.
2. `user.rewardDebt` is updated only after the external call to ERC1155 callback.

During withdrawal, the attacker could only retrieve their initial deposit since `user.amount` wasn't updated during the reentrancy. Instead, they used their inflated balance in PointFarm to redeem a LootRealms NFT in the PointShop contract. This is a classic reentrancy vulnerability that does not follow the check-effect-interaction pattern.. https://twitter.com/DecurityHQ/status/1703096116047421863

Vulnerable code:
function deposit(uint256 _pid, uint256 _amount) public {
    PoolInfo storage pool = poolInfo[_pid];
    UserInfo storage user = userInfo[_pid][msg.sender];
    updatePool(_pid);
    if (user.amount > 0) {
        uint256 pending = user.amount.mul(pool.accPointsPerShare).div(1e18).sub(user.rewardDebt);
        if (pending > 0) {
            bytes memory data;
            _mint(msg.sender, _pid, pending, data);
        }
    }
    if (_amount > 0) {
        pool.uToken.safeTransferFrom(address(msg.sender), address(this), _amount);
        user.amount = user.amount.add(_amount);
    }
    user.rewardDebt = user.amount.mul(pool.accPointsPerShare).div(1e18);
    emit Deposit(msg.sender, _pid, _amount);
}

Vulnerability type: Business Logic Flaw, Reentrancy
HIGH severity: DKP — The contract was not verified. So, after decompiling it, we found that the vulnerability was present in the exchange() function, which was used to swap USDT for DKP tokens. The problem arises because the price Oracle relies on the balance ratio of the two tokens in the USDT-DKP pair, making it vulnerable to flash loan attacks that allow the attacker to manipulate the pool.. https://twitter.com/CertiKAlert/status/1633421908996763648 https://blog.solidityscan.com/dkp-hack-analysis-improper-token-pair-ratio-calculation-282672cd0450 https://medium.com/coinmonks/decoding-dkp-token-s-80k-exploit-quillaudits-45c67df973d6

Vulnerable code:
function exchange(uint256 varg0) public payable {
    require(4 + (msg.data.length - 4) >= 32);
    require(msg.sender.code.size > 0, Error('no isContract'));
    require(varg0 >= stor_9, Error('num >= proper'));
    v0 = _SafeAdd(varg0, owner[msg.sender]);
    owner[msg.sender] = v0;
    0xa169(varg0, stor_10, msg.sender, _usdt);
    require(owner[6].code.size);
    (v1, v3, v8) = owner_e_0_a9.staticcall(0x0bds2903, msg.sender).gas(msg.gas);
    require(v1); // checks call status, propagates error data on error
    require(MEM[64] + RETURNDATASIZE() >= 96);
    v2 = 0x2a16(v2);
    v5 = 0x1201();
    v6 = 0x1aF2(varg0, v5);
    v7 = 0x1b6d(0x0de0b6b3a7640000, v6);
    v8 = v9 = 0;
    if (address(v2) != 0) {
        // logic here
    }
    if (address(v3) != 0) {
        // logic here
    }
    if (address(v4) != 0) {
        // logic here
        0x1aF4(stor_8, v7);
        0x1b6d(_exchange, v2);
    }
    // additional logic
    v2 = SafeSub(v2, v7);
    // emit event or return statement
    emit Swap(msg.sender, stor_3_19);
} ... function 0x1201() private { 
    require(stor_3_0_19.code.size);
    (v0, v1) = stor_3_0_19.balanceOf(_lp).gas(msg.gas);
    require(v0); // checks call status, propagates error data on error
    MEM[64] = MEM[64] + (RETURNDATASIZE() + 31 & ~0x1f);
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    0x2a44(v1);
    require(_usdt.code.size);
    (v2, v3) = _usdt.balanceOf(_lp).gas(msg.gas);
    require(v2); // checks call status, propagates error data on error
    MEM[64] = MEM[64] + (RETURNDATASIZE() + 31 & ~0x1f);
    require(MEM[64] + RETURNDATASIZE() - MEM[64] >= 32);
    0x2a44(v3);
    v4 = 0x1af2(0xde0b6b3a7640000, v1);
    v5 = 0x1b6d(v3, v4);
    return v5;
}

Vulnerability type: Flashloans, Price Manipulation
HIGH severity: Cream Finance — Reentrancy via ERC777 hook. Use tokensReceived hook to reenter borrow(). use tokensReceived hook to reenter borrow()

Vulnerable code:
function borrow(uint256 borrowAmount) external returns (uint256) {
    return borrowInternal(borrowAmount, false);
}

function _transferByPartition(
    bytes32 _fromPartition,
    address _operator,
    address _from,
    address _to,
    uint256 _value,
    bytes memory _data,
    bytes memory _operatorData
) internal returns (bytes32) {
    require(_to != address(0), EC_57_INVALID_RECEIVER);

    // If the `_operator` is attempting to transfer from a different `_from`
    // address, first check that they have the requisite operator or
    // allowance permissions.
    if (_from != _operator) {
        require(
            _isOperatorForPartition(_fromPartition, _operator, _from) ||
            (_value <= _allowedByPartition[_fromPartition][_from][_operator]),
            EC_53_INSUFFICIENT_ALLOWANCE
        );

        // If the sender has an allowance for the partition, that should
        // be decremented
        if (_allowedByPartition[_fromPartition][_from][_operator] >= _value) {
            _allowedByPartition[_fromPartition][_from][msg.sender] = _allowedByPartition[_fromPartition][_from][_operator].sub(
                _value
            );
        } else {
            _allowedByPartition[_fromPartition][_from][_operator] = 0;
        }
    }

    _callPreTransferHooks( //vulnerable point, call hook
        _fromPartition,
        _operator,
        _from,
        _to,
        _value,
        _data,
        _operatorData
    );

    require(
        _balanceOfByPartition[_from][_fromPartition] >= _value,
        EC_52_INSUFFICIENT_BALANCE
    );

    bytes32 toPartition = PartitionUtils._getDestinationPartition(
        _data,
        _fromPartition
    );

    _removeTokenFromPartition(_from, _fromPartition, _value);
    _addTokenToPartition(_to, toPartition, _value);
    _callPostTransferHooks(
        toPartition,
        _operator,
        _from,
        _to,
        _value,
        _data,
        _operatorData
    );

    emit Transfer(_from, _to, _value);
    emit TransferByPartition(
        _fromPartition,
        _operator,
        _from,
        _to,
        _value,
        _data,
        _operatorData
    );

    if (toPartition != _fromPartition) {
        emit ChangedPartition(_fromPartition, toPartition, _value);
    }

    return toPartition;
}

Vulnerability type: ERC777, Reentrancy, lending
HIGH severity: Balancer — The attack exploited a rounding down issue in the linear pools, letting the attacker manipulate the token exchange rate in the composable pool. By reducing BPT supply to zero and then performing a reverse swap, they achieved a nearly 1:1 exchange rate, which was lower than the linear pool's rate. https://slowmist.medium.com/review-and-recommendations-of-balancer-incident-d2b31b5bd863 https://medium.com/balancer-protocol/rate-manipulation-in-balancer-boosted-pools-technical-postmortem-53db4b642492 https://blocksecteam.medium.com/yet-another-risk-posed-by-precision-loss-an-in-depth-analysis-of

Vulnerable code:
function onSwap(
    SwapRequest memory request,
    uint256[] memory balances,
    uint256 indexIn,
    uint256 indexOut
) public view override onlyVault(request.poolId) whenNotPaused returns (uint256) {
    // In most Pools, swaps involve exchanging one token held by the Pool for another. In this case however, since
    // one of the three tokens is the BPT itself, a swap might also be a join (main/wrapped for BPT) or an exit
    // (BPT for main/wrapped).
    // All three swap types (swaps, joins and exits) are fully disabled if the emergency pause is enabled. Under
    // these circumstances, the Pool should be exited using the regular Vault.exitPool function.

    // Sanity check: this is not entirely necessary as the Vault's interface enforces the indices to be valid, but
    // the check is cheap to perform.
    _require(indexIn < _TOTAL_TOKENS && indexOut < _TOTAL_TOKENS, Errors.OUT_OF_BOUNDS);

    // Note that we already know the indices of the main token, wrapped token and BPT, so there is no need to pass
    // these indices to the inner functions.

    // Upscale balances by the scaling factors (taking into account the wrapped token rate)
    uint256[] memory scalingFactors = _scalingFactors();
    _upscaleArray(balances, scalingFactors);

    (uint256 lowerTarget, uint256 upperTarget) = getTargets();
    LinearMath.Params memory params = LinearMath.Params({
        fee: getSwapFeePercentage(),
        lowerTarget: lowerTarget,
        upperTarget: upperTarget
    });

    if (request.kind == IVault.SwapKind.GIVEN_IN) {
        // The amount given is for token in, the amount calculated is for token out
        request.amount = _upscale(request.amount, scalingFactors[indexIn]);
        uint256 amountOut = _onSwapGivenIn(request, balances, params);

        // amountOut tokens are exiting the Pool, so we round down.
        return _downscaleDown(amountOut, scalingFactors[indexOut]);
    } else {
        // The amount given is for token out, the amount calculated is for token in
        request.amount = _upscale(request.amount, scalingFactors[indexOut]);
        uint256 amountIn = _onSwapGivenOut(request, balances, params);

        // amountIn tokens are entering the Pool, so we round up.
        return _downscaleUp(amountIn, scalingFactors[indexIn]);
    }
}

Vulnerability type: Vulnerability
HIGH severity: SCROLL — Integer Underflow. Anyone can transfer tokens to owner address even though he has no tokens. I have simulated it. Strange! According to decompile, solidity version is 0.8.19. How is underflow possible?. https://x.com/0xNickLFranklin/status/1795650745448169741

Vulnerable code:
// 2024.05.26 23:45 UTC
// Compiled using the solidity compiler version 0.8.19

// Data structures and variables inferred from the use of storage ins...
mapping (uint256 => uint256) _totalSupply; // STORAGE[0x1]
mapping (uint256 => mapping (uint256 => uint256)) _allowance; // STORAGE

Vulnerability type: Under/Overflow
HIGH severity: DODO — Incorrect access control. The init() function in the pool creation contract could be called multiple times, leading to repeated initializations. The attackers took advantage of this and borrowed out the tokens in the liquidity pools using flash loans. The pool contract was then initialized again and counterfeit tokens created by the attackers were returned in lieu of the original tokens, bypassing the flash loan return check logic.. The init() function in the pool creation contract could be called multiple times, leading to repeated initializations. The attackers took advantage of this and borrowed out the tokens in the liquidity pools using flash loans. The pool contract was then initialized again and counterfeit tokens create

Vulnerable code:
function init(   
        address maintainer,
        address baseTokenAddress,
        address quoteTokenAddress,
        uint256 lpFeeRate,
        address mtFeeRateModel,
        uint256 i,
        uint256 k,
        bool isOpenTWAP
    ) external { //vulnerable point
        require(baseTokenAddress != quoteTokenAddress, "BASE_QUOTE_CAN_NOT_BE_SAME");
        _BASE_TOKEN_ = IERC20(baseTokenAddress);
        _QUOTE_TOKEN_ = IERC20(quoteTokenAddress);

        require(i > 0 && i <= 10**36);
        _I_ = i;

        require(k <= 10**18);
        _K_ = k;

        _LP_FEE_RATE_ = lpFeeRate;
        _MT_FEE_RATE_MODEL_ = IFeeRateModel(mtFeeRateModel);
        _MAINTAINER_ = maintainer;

        _IS_OPEN_TWAP_ = isOpenTWAP;
        if(isOpenTWAP) _BLOCK_TIMESTAMP_LAST_ = uint32(block.timestamp % 2**32);

        string memory connect = "_";
        string memory suffix = "DLP";

        name = string(abi.encodePacked(suffix, connect, addressToShortString(address(this))));
        symbol = "DLP";
        decimals = _BASE_TOKEN_.decimals();

        // ============================== Permit ====================================
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                // keccak256('EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'),
                0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f,
                keccak256(bytes(name)),
                keccak256(bytes("1")),
                chainId,
                address(this)
            )
        );
        // ========================================================================== 
    }

Vulnerability type: Access Control, Dex/AMM
HIGH severity: FloorProtocol — Attackers exploited the vulnerability by calling the multicall function in the Forwarder contract, altering the last 20 bytes of calldata to the attacker's address to execute the attack.. https://medium.com/@Jingkangchua/vulnerability-analysis-erc2771-multicall-545cad1f9028 https://blog.verichains.io/p/address-spoofing-attack-the-combination

Vulnerable code:
struct ForwardRequest {
    address from;
    address to;
    uint256 value;
    uint256 gas;
    uint256 nonce;
    bytes data;
}

function execute(ForwardRequest calldata req, bytes calldata signature) public payable returns (bool, bytes memory) {
    // Here verify signature signer == req.from
    (bool success, bytes memory result) = req.to.call{ gas: req.gas, value: req.value }(
        abi.encodePacked(req.data, req.from) // append Sender here
    );
    // check gas and return
    return (success, result);
} ... bytes memory dataTransfer = abi.encodePacked(
    abi.encodeWithSelector(
        iTOKEN.transfer.selector,
        attacker,
        iTOKEN(token).balanceOf(victim) / 10 ** 18 * 10 ** 18
    ),
    victim
);

bytes;
arrBytes[0] = dataTransfer;
bytes memory dataMulticall = abi.encodeWithSelector(iTOKEN.multicall.selector, arrBytes);

Vulnerability type: Business Logic Flaw
HIGH severity: LeetSwap — This exploit was a result of incorrect access control, where the _transferFeesSupportingTaxTokens() function  was incorrectly marked as public. This enabled the attacker to misuse the function to transfer tokens to LeetSwap's fee collection address, reducing axlUSD token liquidity and artificially inflating its price for their own gain.. https://twitter.com/BlockSecTeam/status/1686217464051539968 https://twitter.com/peckshield/status/1686209024587710464

Vulnerable code:
function _transferFeesSupportingTaxTokens(address token, uint256 amount)
        public
        returns (uint256) {
    if (amount == 0) {
        return 0;
    }

    uint256 balanceBefore = IERC20(token).balanceOf(fees);
    _safeTransfer(token, fees, amount);
    uint256 balanceAfter = IERC20(token).balanceOf(fees);

    return balanceAfter - balanceBefore;
}

Vulnerability type: Access Control, Price Manipulation
HIGH severity: MIC — There is a vulnerability that enables LP holders to claim LP fees repeatedly.. https://x.com/MetaSec_xyz/status/1742484748239536173

Vulnerable code:
function swapAndSendLPFee(address _addr) private {
    if (blackListed[_addr] && blackListSwitch) {
        return;
    }
    uint256 balance = IUniswapV2Pair(uniswapPair).balanceOf(_addr);
    if (amountLPFee >= 1 * (10 ** 18) && balance > 0) { 
        uint256 total = IUniswapV2Pair(uniswapPair).totalSupply();
        uint256 fee = amountLPFee.mul(balance).div(total);
        if (fee >= 1 * (10 ** 13)) {
            uint256 initialCAKEBalance = IERC20(usdt).balanceOf(address(this));
            swapTokensForCake(fee);
            uint256 newBalance = (IERC20(usdt).balanceOf(address(this))).sub(initialCAKEBalance);
            IERC20(usdt).transfer(_addr, newBalance);
            amountLPFee = amountLPFee.sub(fee);
            emit swapAndSendLPFeeEvent(_addr, fee);
        }
    }
}

Vulnerability type: Incorrect logic
HIGH severity: TomInu Token — Reflective token skim abuse. Tom Inu is a reflective token, aka each time a transfer happens holders will earn fees from it. 1. The Attacker Flashloan many WETH 2. Swap many WETH -> Tom Inu tokens, giving Uniswapv2 Pair large fees 3. Call skim on the Pair (gets fee). The skim function will balance the supply of pair and send the excess funds to the specified address. 4. Swap Tom Inu to WETH for profit. https://twitter.com/libevm/status/1618731761894309889

Vulnerable code:
function deliver(uint256 tAmount) public {
    address sender = _msgSender();
    require(!_isExcluded[sender], "Excluded addresses cannot call this function");
    (uint256 rAmount,,,,,) = _getValues(tAmount);
    _rOwned[sender] = _rOwned[sender].sub(rAmount);
    _rTotal = _rTotal.sub(rAmount);
    _tFeeTotal = _tFeeTotal.add(tAmount);
}

Vulnerability type: Flashloans, skim
HIGH severity: Paribus — Reentrancy, doTransferOut() before updating variables. https://twitter.com/Phalcon_xyz/status/1645742620897955842 https://twitter.com/BlockSecTeam/status/1645744655357575170 https://twitter.com/peckshield/status/1645742296904929280

Vulnerable code:
function redeemInternal(uint redeemTokens) internal nonReentrant returns (uint) { // @audit: useless ReentrancyGuard since it was a cross-contract attack
  accrueInterest();

  return redeemFresh(msg.sender, redeemTokens, 0);
}

function redeemFresh(address payable redeemer, uint redeemTokensIn, uint redeemAmountIn) internal returns (uint) {  
  ...
	vars.totalSupplyNew = sub_(totalSupply, vars.redeemTokens, 'REDEEM_TOO_MUCH');
	vars.accountTokensNew = sub_(accountTokens[redeemer], vars.redeemTokens, 'REDEEM_TOO_MUCH');

	doTransferOut(redeemer, vars.redeemAmount); //vulnerable point

  // @audit: vital variables are updated after interaction (doTransferOut)
totalSupply = vars.totalSupplyNew;
	accountTokens[redeemer] = vars.accountTokensNew;

	comptroller.redeemVerify();
}

Vulnerability type: Reentrancy
HIGH severity: TCH — Signature Malleability Vulnerability,  `0, 1` instead of `27, 28` (previous sigs) to achieve malleability. As a result the attacker burned lots of TCH tokens owned by the PancakeSwap pair, which allowed him to manipulate the price in the pool and take the profit.. https://x.com/DecurityHQ/status/1791180322882629713

Vulnerable code:
function burnToken(uint256 amount, uint256 nonce, bytes memory signature) external {
    bytes32 signatureHash = keccak256(signature);
    require(!usedSignatures[signatureHash], "Signature has already been used");
    require(isAuthorizedSigner(amount, nonce, signature), "Invalid or unauthorized signature");
    usedSignatures[signatureHash] = true;
    uint256 deflationAmount = balances[uniswapV2Pair] * deflationFee / 10000;
    balances[uniswapV2Pair] -= deflationAmount;
    balances[address(0xdead)] += deflationAmount;
    emit Transfer(uniswapV2Pair, address(0xdead), deflationAmount);
    IUniswapV2Pair(uniswapV2Pair).sync();
}

function isAuthorizedSigner(uint256 amount, uint256 nonce, bytes memory signature) internal view returns (bool) {
    bytes32 message = keccak256(abi.encodePacked(address(this), amount, nonce));
    bytes32 ethSignedMessage = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", message));
    return recoverSigner(ethSignedMessage, signature) == authorizedSigner;
}

function recoverSigner(bytes32 ethSignedMessage, bytes memory signature) internal pure returns (address) {
    (bytes32 r, bytes32 s, uint8 v) = splitSignature(signature);
    return ecrecover(ethSignedMessage, v, r, s); // <-- vulnerable point if v either 27 or 28 will return 0
}

Vulnerability type: Signature
HIGH severity: Spherax USDs — Flawed internal accounting systems. USDS has three different accounting systems, two separate auto-migration systems, and all share the same variables, just interpret their meaning differently. Thus, all account variables have to be updated together in order to accurately calculate a user's balance. However, due to improper implementation, these critical updates were not performed accurately, leading to the attack.. https://medium.com/sperax/usds-feb-3-exploit-report-from-engineering-team-9f0fd3cef00c https://twitter.com/danielvf/status/1621965412832350208

Vulnerable code:
function isRebasing(address user) private {
    isRebasing = Address.hasCode(user);
    // Changing this affects balance calculations
    if (isRebasing) {
        if (_nonRebasingCreditsPerToken[user] == 0) {
            // These should be updated together
            _nonRebasingCreditsPerToken[user] = 1;
            if (_balanceOf[user]) {
                uint256 oldBalance = calculateBalance(user);
                _nonRebasingSupply += oldBalance;
                _balanceOf[user] = oldBalance;
            }
        }
    }
    return _nonRebasingCreditsPerToken[user];
}

Vulnerability type: Incorrect logic, Math