Farseen0/scar-pairs huggingface dataset:
HIGH severity: Risk of reuse of signatures across forks due to lack of chain ID validation. ERC20Permit contract implements EIP-2612 functionality but lacks chain ID validation, enabling signature replay attacks across different forks.

Vulnerable code:
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Permit.sol)

pragma solidity ^0.8.20;

import {IERC20Permit} from "./IERC20Permit.sol";
import {ERC20} from "../ERC20.sol";
import {ECDSA} from "../../../utils/cryptography/ECDSA.sol";
import {EIP712} from "../../../utils/cryptography/EIP712.sol";
import {Nonces} from "../../../utils/Nonces.sol";

/**
 * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
abstract contract ERC20Permit is ERC20, IERC20Permit, EIP712, Nonces {
    bytes32 private constant PERMIT_TYPEHASH =
        keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");

    /**
     * @dev Permit deadline has expired.
     */
    error ERC2612ExpiredSignature(uint256 deadline);

    /**
     * @dev Mismatched signature.
     */
    error ERC2612InvalidSigner(address signer, address owner);

    /**
     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
     *
     * It's a good idea to use the same `name` that is defined as the ERC20 token name.
     */
    constructor(string memory name) EIP712(name, "1") {}

    /**
     * @inheritdoc IERC20Permit
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) public virtual {
        if (block.timestamp > deadline) {
            revert ERC2612ExpiredSignature(deadline);
        }

        bytes32 structHash = keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, _useNonce(owner), deadline));

        bytes32 hash = _hashTypedDataV4(structHash);

        address signer = ECDSA.recover(hash, v, r, s);
        if (signer != owner) {
            revert ERC2612InvalidSigner(signer, owner);
        }

        _approve(owner, spender, value);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    function nonces(address owner) public view virtual override(IERC20Permit, Nonces) returns (uint256) {
        return super.nonces(owner);
    }

    /**
     * @inheritdoc IERC20Permit
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view virtual returns (bytes32) {
        return _domainSeparatorV4();
    }
}


Vulnerability type: CWE-693|CWE-345|CWE-347
HIGH severity: Ownership transfers can be front-run. Anyone can call the transferPerpOwner function to set their address as the owner, taking ownership of a contract's vBase or vQuote tokens.

Vulnerable code:
// SPDX-License-Identifier: AGPL-3.0
pragma solidity ^0.8.16;

/// @notice Emitted when the sender is not perp
error PerpOwnable_NotOwner();

/// @notice Emitted when the proposed address is equal to the zero address
error PerpOwnable_TransferZeroAddress();

/// @notice Perp access control contract, simplified of OpenZeppelin's Ownable.sol
/// @dev Ownership can only be transferred once
contract PerpOwnable {
    address public perp;

    event PerpOwnerTransferred(address indexed sender, address indexed recipient);

    constructor() {
        // at deployment, `perp` is going to be `deployer`
        perp = msg.sender;

        emit PerpOwnerTransferred(address(0), msg.sender);
    }

    /// @notice Access control modifier that requires modified function to be called by the perp contract
    modifier onlyPerp() {
        if (msg.sender != perp) revert PerpOwnable_NotOwner();
        _;
    }

    /// @notice Transfer `perp` account
    /// @notice Can only be used at deployment as Perpetual can't transfer ownership afterwards
    /// @param recipient Account granted `perp` access control
    function transferPerpOwner(address recipient) external onlyPerp {
        if (recipient == address(0)) revert PerpOwnable_TransferZeroAddress();

        perp = recipient;
        emit PerpOwnerTransferred(msg.sender, recipient);
    }
}


Vulnerability type: CWE-284
HIGH severity: OTUT - Transfers User's Tokens. The contract allows any user to transfer the balance of a user's address if they have granted allowance, without subtracting the allowance.

Vulnerable code:
pragma solidity ^0.8.19;

//SPDX-License-Identifier: Apache-2.0





contract TrebolToken {

    mapping(address => uint) public balances;

    mapping(address => mapping(address => uint)) public allowance;

    uint public totalSupply = 23000000000 * 10 ** 18;

    string public name = "TrebolToken";

    string public symbol = "TT";

    uint public decimals = 18;

   

    event Transfer(address indexed from, address indexed to, uint value);

    event Approval(address indexed owner, address indexed spender, uint value);

   

    constructor() {

        balances[msg.sender] = totalSupply;

    }

   

    function balanceOf(address owner) public view returns(uint) {

        return balances[owner];

    }

   

    function transfer(address to, uint value) public returns(bool) {

        require(balanceOf(msg.sender) >= value, 'balance too low');

        balances[to] += value;

        balances[msg.sender] -= value;

       emit Transfer(msg.sender, to, value);

        return true;

    }

   

    function transferFrom(address from, address to, uint value) public returns(bool) {

        require(balanceOf(from) >= value, 'balance too low');

        require(allowance[from][msg.sender] >= value, 'allowance too low');

        balances[to] += value;

        balances[from] -= value;

        emit Transfer(from, to, value);

        return true;   

    }

   

    function approve(address spender, uint value) public returns (bool) {

        allowance[msg.sender][spender] = value;

        emit Approval(msg.sender, spender, value);

        return true;   

    }

}

Vulnerability type: CWE-284|CWE-285|CWE-863
HIGH severity: Linearization of exponential compounding could lead to insolvency. Incorrect implementation of money market rate per second calculation, leading to potential system insolvency.

Vulnerable code:
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity 0.8.3;

import {
    Initializable
} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import {DecMath} from "../../libs/DecMath.sol";
import {IInterestOracle} from "./IInterestOracle.sol";
import {IMoneyMarket} from "../../moneymarkets/IMoneyMarket.sol";

contract EMAOracle is IInterestOracle, Initializable {
    using DecMath for uint256;

    uint256 internal constant PRECISION = 10**18;

    /**
        Immutable parameters
     */
    uint256 public UPDATE_INTERVAL;
    uint256 public UPDATE_MULTIPLIER;
    uint256 public ONE_MINUS_UPDATE_MULTIPLIER;

    /**
        Public variables
     */
    uint256 public emaStored;
    uint256 public lastIncomeIndex;
    uint256 public lastUpdateTimestamp;

    /**
        External contracts
     */
    IMoneyMarket public override moneyMarket;

    function initialize(
        uint256 _emaInitial,
        uint256 _updateInterval,
        uint256 _smoothingFactor,
        uint256 _averageWindowInIntervals,
        address _moneyMarket
    ) external initializer {
        emaStored = _emaInitial;
        UPDATE_INTERVAL = _updateInterval;
        lastUpdateTimestamp = block.timestamp;

        uint256 updateMultiplier =
            _smoothingFactor / (_averageWindowInIntervals + 1);
        UPDATE_MULTIPLIER = updateMultiplier;
        ONE_MINUS_UPDATE_MULTIPLIER = PRECISION - updateMultiplier;

        moneyMarket = IMoneyMarket(_moneyMarket);
        lastIncomeIndex = moneyMarket.incomeIndex();
    }

    function updateAndQuery()
        public
        override
        returns (bool updated, uint256 value)
    {
        uint256 timeElapsed = block.timestamp - lastUpdateTimestamp;
        if (timeElapsed < UPDATE_INTERVAL) {
            return (false, emaStored);
        }

        // save gas by loading storage variables to memory
        uint256 _lastIncomeIndex = lastIncomeIndex;
        uint256 _emaStored = emaStored;

        uint256 newIncomeIndex = moneyMarket.incomeIndex();
        uint256 incomingValue =
            (newIncomeIndex - _lastIncomeIndex).decdiv(_lastIncomeIndex) /
                timeElapsed;

        updated = true;
        value =
            (incomingValue *
                UPDATE_MULTIPLIER +
                _emaStored *
                ONE_MINUS_UPDATE_MULTIPLIER) /
            PRECISION;
        emaStored = value;
        lastIncomeIndex = newIncomeIndex;
        lastUpdateTimestamp = block.timestamp;
    }

    function query() public view override returns (uint256 value) {
        return emaStored;
    }

    uint256[43] private __gap;
}


Vulnerability type: CWE-682
HIGH severity: ERC20Wrapper's transferFrom function ignores the sender argument. The function ignores the sender argument, causing unexpected token transfers.

Vulnerable code:
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/ERC20Wrapper.sol)

pragma solidity ^0.8.0;

import "../ERC20.sol";
import "../utils/SafeERC20.sol";

/**
 * @dev Extension of the ERC20 token contract to support token wrapping.
 *
 * Users can deposit and withdraw "underlying tokens" and receive a matching number of "wrapped tokens". This is useful
 * in conjunction with other modules. For example, combining this wrapping mechanism with {ERC20Votes} will allow the
 * wrapping of an existing "basic" ERC20 into a governance token.
 *
 * _Available since v4.2._
 */
abstract contract ERC20Wrapper is ERC20 {
    IERC20 public immutable underlying;

    constructor(IERC20 underlyingToken) {
        underlying = underlyingToken;
    }

    /**
     * @dev Allow a user to deposit underlying tokens and mint the corresponding number of wrapped tokens.
     */
    function depositFor(address account, uint256 amount) public virtual returns (bool) {
        SafeERC20.safeTransferFrom(underlying, _msgSender(), address(this), amount);
        _mint(account, amount);
        return true;
    }

    /**
     * @dev Allow a user to burn a number of wrapped tokens and withdraw the corresponding number of underlying tokens.
     */
    function withdrawTo(address account, uint256 amount) public virtual returns (bool) {
        _burn(_msgSender(), amount);
        SafeERC20.safeTransfer(underlying, account, amount);
        return true;
    }

    /**
     * @dev Mint wrapped token to cover any underlyingTokens that would have been transfered by mistake. Internal
     * function that can be exposed with access control if desired.
     */
    function _recover(address account) internal virtual returns (uint256) {
        uint256 value = underlying.balanceOf(address(this)) - totalSupply();
        _mint(account, value);
        return value;
    }
}


Vulnerability type: CWE-284|CWE-285|CWE-863
HIGH severity: Token stealing. The to function can be used to make arbitrary calls on behalf of the Lighthouse contract

Vulnerable code:
pragma solidity ^0.4.24;

import './LighthouseAPI.sol';
import './LighthouseABI.sol';
import './LiabilityFactory.sol';

contract LighthouseLib is LighthouseAPI, LighthouseABI {

    function refill(uint256 _value) external {
        require(xrt.transferFrom(msg.sender, this, _value));
        require(_value >= minimalFreeze);

        if (balances[msg.sender] == 0) {
            indexOf[msg.sender] = members.length;
            members.push(msg.sender);
        }
        balances[msg.sender] += _value;
    }

    function withdraw(uint256 _value) external {
        require(balances[msg.sender] >= _value);

        require(xrt.transfer(msg.sender, _value));
        balances[msg.sender] -= _value;

        // Drop member if quota go to zero
        if (quotaOf(msg.sender) == 0) {
            require(xrt.transfer(msg.sender, balances[msg.sender])); 
            balances[msg.sender] = 0;
            
            uint256 senderIndex = indexOf[msg.sender];
            uint256 lastIndex = members.length - 1;
            if (senderIndex < lastIndex)
                members[senderIndex] = members[lastIndex];
            members.length -= 1;
        }
    }

    function nextMember() internal
    { marker = (marker + 1) % members.length; }

    modifier quoted {
        if (quota == 0) {
            // Step over marker
            nextMember();

            // Allocate new quota
            quota = quotaOf(members[marker]);
        }

        // Consume one quota for transaction sending
        quota -= 1;

        _;
    }

    modifier keepalive {
        if (timeoutBlocks < block.number - keepaliveBlock) {
            // Search keepalive sender
            while (msg.sender != members[marker])
                nextMember();

            // Allocate new quota
            quota = quotaOf(members[marker]);
        }

        _;
    }

    modifier member {
        // Zero members guard
        require(members.length > 0);

        // Only member with marker can to send transaction
        require(msg.sender == members[marker]);

        // Store transaction sending block
        keepaliveBlock = block.number;

        _;
    }

    function to(address _to, bytes _data) external keepalive quoted member
    { require(_to.call(_data)); }

    function () external keepalive quoted member
    { require(factory.call(msg.data)); }
}


Vulnerability type: CWE-284
HIGH severity: Unvalidated extra data in CollateralToken callback. An attacker can spoof extra data and take advantage of this vulnerability, allowing them to own an NFT token and receive the loaned amount from a public vault.

Vulnerable code:
// SPDX-License-Identifier: Unlicensed

pragma solidity 0.7.6;

import "../oz_modified/ICHIERC20.sol";

contract CollateralToken is ICHIERC20 {

    constructor() {
        initERC20("Collateral Token", "CTTest");
        _mint(msg.sender, 1000 * 10 ** 18);
    }

}


Vulnerability type: CWE-284|CWE-285|CWE-862
HIGH severity: Unlimited Kresko asset minting due to not considering the accrued interest when burning assets. Removing Kresko assets from mintedKreskoAssets array when burning assets with accrued interest, allowing unlimited minting of debt without risk of future liquidation.

Vulnerable code:
// SPDX-License-Identifier: BUSL-1.1
pragma solidity >=0.8.20;

import {IBurnFacet} from "../interfaces/IBurnFacet.sol";
import {Arrays} from "../../libs/Arrays.sol";
import {Error} from "../../libs/Errors.sol";
import {Role} from "../../libs/Authorization.sol";
import {MinterEvent} from "../../libs/Events.sol";

import {MinterModifiers} from "../MinterModifiers.sol";
import {DiamondModifiers} from "../../diamond/DiamondModifiers.sol";
import {Action} from "../MinterTypes.sol";
import {ms, MinterState} from "../MinterStorage.sol";
import {irs} from "../InterestRateState.sol";

/**
 * @author Kresko
 * @title BurnFacet
 * @notice Main end-user functionality concerning burning of kresko assets
 */
contract BurnFacet is DiamondModifiers, MinterModifiers, IBurnFacet {
    using Arrays for address[];

    /// @inheritdoc IBurnFacet
    function burnKreskoAsset(
        address _account,
        address _kreskoAsset,
        uint256 _burnAmount,
        uint256 _mintedKreskoAssetIndex
    ) external nonReentrant kreskoAssetExists(_kreskoAsset) onlyRoleIf(_account != msg.sender, Role.MANAGER) {
        require(_burnAmount > 0, Error.ZERO_BURN);
        MinterState storage s = ms();

        if (s.safetyStateSet) {
            ensureNotPaused(_kreskoAsset, Action.Repay);
        }

        // Get accounts principal debt
        uint256 debtAmount = s.getKreskoAssetDebtPrincipal(_account, _kreskoAsset);

        if (_burnAmount != type(uint256).max) {
            require(_burnAmount <= debtAmount, Error.KRASSET_BURN_AMOUNT_OVERFLOW);
            // Ensure principal left is either 0 or >= minDebtValue
            _burnAmount = s.ensureNotDustPosition(_kreskoAsset, _burnAmount, debtAmount);
        } else {
            // _burnAmount of uint256 max, burn all principal debt
            _burnAmount = debtAmount;
        }

        // If sender repays all principal debt of asset with no stability rate, remove it from minted assets array.
        // For assets with stability rate the revomal is done when repaying interest
        if (irs().srAssets[_kreskoAsset].asset == address(0) && _burnAmount == debtAmount) {
            s.mintedKreskoAssets[_account].removeAddress(_kreskoAsset, _mintedKreskoAssetIndex);
        }
        // Charge the burn fee from collateral of _account
        s.chargeCloseFee(_account, _kreskoAsset, _burnAmount);

        // Record the burn
        s.burn(_kreskoAsset, s.kreskoAssets[_kreskoAsset].anchor, _burnAmount, _account);

        // Emit logs
        emit MinterEvent.KreskoAssetBurned(_account, _kreskoAsset, _burnAmount);
    }
}


Vulnerability type: CWE-664
MEDIUM severity: Inability to retrieve sent native tokens. Native tokens sent to the contract cannot be retrieved.

Vulnerable code:
// SPDX-License-Identifier: CC0-1.0
pragma solidity ^0.8.0;

/******************************************************************************\
* Author: Nick Mudge <nick@perfectabstractions.com>, Twitter/Github: @mudgen
* EIP-2535 Diamonds
*
* Implementation of a diamond.
/******************************************************************************/

import { LibDiamond } from "./libraries/LibDiamond.sol";
import { IDiamondCut } from "./interfaces/IDiamondCut.sol";
import { IDiamondLoupe } from "./interfaces/IDiamondLoupe.sol";
import { IERC173 } from "./interfaces/IERC173.sol";
import { IERC165 } from "./interfaces/IERC165.sol";

// solhint-disable no-complex-fallback
// solhint-disable no-inline-assembly
// solhint-disable no-empty-blocks

// When no function exists for function called
error FunctionNotFound(bytes4 _functionSelector);

// This is used in diamond constructor
// more arguments are added to this struct
// this avoids stack too deep errors
struct DiamondArgs {
  address owner;
  address init;
  bytes initCalldata;
}

contract Diamond {
  constructor(IDiamondCut.FacetCut[] memory _diamondCut, DiamondArgs memory _args) payable {
    LibDiamond.setContractOwner(_args.owner);
    LibDiamond.diamondCut(_diamondCut, _args.init, _args.initCalldata);

    // Code can be added here to perform actions and set state variables.
  }

  // Find facet for function that is called and execute the
  // function if a facet is found and return any value.
  fallback() external payable {
    LibDiamond.DiamondStorage storage ds;
    bytes32 position = LibDiamond.DIAMOND_STORAGE_POSITION;
    // get diamond storage
    assembly {
      ds.slot := position
    }
    // get facet from function selector
    address facet = ds.facetAddressAndSelectorPosition[msg.sig].facetAddress;
    if (facet == address(0)) {
      revert FunctionNotFound(msg.sig);
    }
    // Execute external function from facet using delegatecall and return any value.
    assembly {
      // copy function selector and any arguments
      calldatacopy(0, 0, calldatasize())
      // execute function call using the facet
      let result := delegatecall(gas(), facet, 0, calldatasize(), 0, 0)
      // get any return value
      returndatacopy(0, 0, returndatasize())
      // return any return value or error back to the caller
      switch result
      case 0 {
        revert(0, returndatasize())
      }
      default {
        return(0, returndatasize())
      }
    }
  }

  receive() external payable {}
}


Vulnerability type: CWE-664|CWE-404|CWE-772
HIGH severity: Token transfer to the wrong account correctness. The transferFrom() function sends tokens to the msg.sender, which is incorrect in certain scenarios.

Vulnerable code:
pragma solidity ^0.4.24;

import "openzeppelin-solidity/contracts/token/ERC20/CappedToken.sol";
import "openzeppelin-solidity/contracts/token/ERC20/PausableToken.sol";

contract OMIToken is CappedToken, PausableToken {
  string public constant name = "Ecomi Token";
  string public constant symbol = "OMI";
  uint256 public decimals = 18;

  function OMIToken() public CappedToken(1000000000*1e18) {}

  /// @dev Function to call from other contracts to ensure that this is the proper contract
  function isOMITokenContract()
    public 
    pure 
    returns(bool)
  { 
    return true; 
  }
}

Vulnerability type: CWE-691|CWE-841
MEDIUM severity: Token does not follow ERC20 Token Standard. Token is missing approve function, making it incompatible with ERC20 standard.

Vulnerable code:
/**
 * SPDX-License-Identifier: UNLICENSED
 */
pragma solidity 0.6.10;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface ERC20Interface {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `recipient`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address recipient, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `sender` to `recipient` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    function decimals() external view returns (uint8);

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);
}


Vulnerability type: CWE-710|CWE-1068