Farseen0/scar-pairs huggingface dataset:
MEDIUM severity: Misleading and Non-Authoritative Whitelist Events in `PermissionedMulticallHandler`. The `PermissionedMulticallHandler` contract emits custom events `CallerWhitelisted` and `CallerRemovedFromWhitelist` via wrapper functions `whitelistCaller` and `removeCallerFromWhitelist`. However, these events are emitted unconditionally, regardless of whether the underlying role state actually ch...

Vulnerable code:
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

import { MulticallHandler } from "./MulticallHandler.sol";
import { AccessControl } from "@openzeppelin/contracts/access/AccessControl.sol";

/**
 * @title PermissionedMulticallHandler
 * @notice Extension of MulticallHandler that restricts access to whitelisted callers
 * @dev Uses OpenZeppelin's AccessControl for caller permission management.
 * Only addresses with the WHITELISTED_CALLER_ROLE can call handleV3AcrossMessage.
 */
contract PermissionedMulticallHandler is MulticallHandler, AccessControl {
    /// @notice Role identifier for whitelisted callers
    bytes32 public constant WHITELISTED_CALLER_ROLE = keccak256("WHITELISTED_CALLER_ROLE");

    /// @notice Emitted when a caller is whitelisted
    event CallerWhitelisted(address indexed caller);

    /// @notice Emitted when a caller is removed from whitelist
    event CallerRemovedFromWhitelist(address indexed caller);

    /// @notice Error thrown when caller is not whitelisted
    error CallerNotWhitelisted(address caller);

    /**
     * @notice Constructor that sets up the initial admin
     * @param admin Address that will have DEFAULT_ADMIN_ROLE
     */
    constructor(address admin) {
        _grantRole(DEFAULT_ADMIN_ROLE, admin);
    }

    /**
     * @notice Overrides handleV3AcrossMessage to add caller whitelist check
     * @dev Only addresses with WHITELISTED_CALLER_ROLE can call this function
     * @param token The token being transferred
     * @param amount The amount of tokens
     * @param relayer The relayer address
     * @param message The encoded Instructions struct
     */
    function handleV3AcrossMessage(
        address token,
        uint256 amount,
        address relayer,
        bytes memory message
    ) public override {
        if (!hasRole(WHITELISTED_CALLER_ROLE, msg.sender)) {
            revert CallerNotWhitelisted(msg.sender);
        }

        // Call parent implementation
        super.handleV3AcrossMessage(token, amount, relayer, message);
    }

    /**
     * @notice Add a caller to the whitelist
     * @param caller Address to whitelist
     */
    function whitelistCaller(address caller) external onlyRole(DEFAULT_ADMIN_ROLE) {
        grantRole(WHITELISTED_CALLER_ROLE, caller);
        emit CallerWhitelisted(caller);
    }

    /**
     * @notice Remove a caller from the whitelist
     * @param caller Address to remove from whitelist
     */
    function removeCallerFromWhitelist(address caller) external onlyRole(DEFAULT_ADMIN_ROLE) {
        revokeRole(WHITELISTED_CALLER_ROLE, caller);
        emit CallerRemovedFromWhitelist(caller);
    }
}


Vulnerability type: CWE-693|CWE-778
MEDIUM severity: Unnecessary `payable` Fallback Function. The `fallback` function in `BaseModuleHandler` is marked `payable`, allowing it to receive native assets, but the target logic in `HyperCoreFlowExecutor` does not contain any `payable` functions.
The root cause is the inclusion of the `payable` modifier without a functional need.
An attacker could s...

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

import { AuthorizedFundedFlow } from "./AuthorizedFundedFlow.sol";
import { HyperCoreFlowExecutor } from "./HyperCoreFlowExecutor.sol";
import { HyperCoreFlowRoles } from "./HyperCoreFlowRoles.sol";

// Note: v5 is necessary since v4 does not use ERC-7201.
import { AccessControlUpgradeable } from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts-v4/security/ReentrancyGuard.sol";

/**
 * @notice Base contract for module handlers that use delegatecall to interact with HyperCoreFlowExecutor
 * @dev Uses AccessControlUpgradeable to ensure storage compatibility with HyperCoreFlowExecutor when using delegatecall
 */
abstract contract BaseModuleHandler is
    AccessControlUpgradeable,
    ReentrancyGuard,
    AuthorizedFundedFlow,
    HyperCoreFlowRoles
{
    /// @notice Address of the underlying hypercore module
    address public immutable hyperCoreModule;

    constructor(address _donationBox, address _baseToken, bytes32 _roleAdmin) {
        hyperCoreModule = address(new HyperCoreFlowExecutor(_donationBox, _baseToken));

        _setRoleAdmin(PERMISSIONED_BOT_ROLE, _roleAdmin);
        _setRoleAdmin(FUNDS_SWEEPER_ROLE, _roleAdmin);
    }

    /// @notice Fallback function to proxy all calls to the HyperCore module via delegatecall
    /// @dev Permissioning is enforced by the delegated function's own modifiers (e.g. onlyPermissionedBot)
    fallback(bytes calldata data) external nonReentrant returns (bytes memory) {
        return _delegateToHyperCore(data);
    }

    /// @notice Internal delegatecall helper
    function _delegateToHyperCore(bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory ret) = hyperCoreModule.delegatecall(data);
        if (!success) {
            assembly {
                revert(add(ret, 32), mload(ret))
            }
        }
        return ret;
    }
}


Vulnerability type: CWE-693
MEDIUM severity: Function Visibility Overly Permissive. Several functions across multiple contracts are declared with more permissive visibility than necessary, which could potentially allow unintended access from derived contracts or external callers. The root cause is the use of `internal` or `public` visibility when `private` or `external` would be su...

Vulnerable code:
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.20;

contract PermissionControl {
    address private administrator_;
    // todo add grants admin
    address [] private grantees_;

    constructor() {
        administrator_ = msg.sender;
    }

    function checkSuperPermission(address _addr) internal view returns(bool) {
        if (_addr == administrator_ || _addr == address(0)) {
            return true;
        }

        return false;
    }

    function checkAdminPermission(address _addr) internal view returns(bool) {
        if (checkSuperPermission(_addr) || checkGrantPermission(_addr)) {
            return true;
        }

        return false;
    }

    function checkGrantPermission(address _addr) internal view returns(bool) {
        for (uint256 i = 0; i < grantees_.length; i++) {
            if (grantees_[i] == _addr) {
                return true;
            }
        }

        return false;
    }

    event SuperTransferred(
        address old_administrator_,
        address new_administrator_
    );
    function tranferSuperAdmin(address _new_admin) external {
        require(checkSuperPermission(msg.sender), "Permission denied");
        require(administrator_ != _new_admin, "Permission denied, same address");

        address old_admin = administrator_;
        administrator_ = _new_admin;
        emit SuperTransferred(old_admin, _new_admin);
    }

    // return administrator_
    function getSuperAdmin() public view returns (address) {
        return administrator_;
    }

    // return administrator_
    function getGranteeAdmin() public view returns ( address[] memory) {
        return grantees_;
    }

    event AdminGranted(
        address grantee
    );
    function grantAdmin(address _addr) external {
        require(checkSuperPermission(msg.sender), "Permission denied");
        require(!checkGrantPermission(_addr), "Address already exist in grantees");

        grantees_.push(_addr);
        emit AdminGranted(_addr);
    }
    event AdminRevoked(
        address revoker
    );
    function revokeAdmin(address _addr) external {
        require(checkSuperPermission(msg.sender), "Permission denied");
        require(checkGrantPermission(_addr), "Address not exist in grantees");

        for (uint256 i = 0; i < grantees_.length; i++) {
            if (grantees_[i] == _addr) {
                grantees_[i] = grantees_[grantees_.length - 1];
                grantees_.pop();
                break;
            }
        }

        emit AdminRevoked(_addr);
    }
}

Vulnerability type: CWE-710|CWE-1076
MEDIUM severity: Anyone can issue approvals for ERC7702 delegatee. The ERC7702TokenApprover module allows anyone to call the approve() function on behalf of a delegatee after they have set code via EIP-7702. This is because the function does not restrict who can invoke it once delegation is active. As a result, any third party can trigger approvals for arbitrary to...

Vulnerable code:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.27;

import { IERC20 } from "@openzeppelin/contracts/interfaces/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import { IERC7702TokenApprover } from "../interfaces/IERC7702TokenApprover.sol";

/**
 * @title ERC7702TokenApprover
 * @notice Contract designed to work with ERC-7702 to batch approve infinite allowances to Permit3
 * @dev This contract is intended to be used as delegation target for EOAs using ERC-7702
 *      Users authorize their EOA to delegatecall to this contract, which then sets infinite
 *      allowances for specified ERC20 tokens to the Permit3 contract.
 */
contract ERC7702TokenApprover is IERC7702TokenApprover {
    using SafeERC20 for IERC20;

    /// @notice The Permit3 contract address that will receive infinite approvals
    address public immutable PERMIT3;

    /**
     * @notice Constructor to set the Permit3 contract address
     * @param permit3 Address of the Permit3 contract
     */
    constructor(
        address permit3
    ) {
        if (permit3 == address(0)) {
            revert ZeroPermit3();
        }
        PERMIT3 = permit3;
    }

    /**
     * @notice Batch approve infinite allowances for multiple ERC20 tokens to Permit3
     * @dev This function is designed to be called via ERC-7702 delegatecall from an EOA
     *      The EOA must have authorized delegation to this contract in the same transaction
     * @param tokens Array of ERC20 token addresses to approve
     */
    function approve(
        address[] calldata tokens
    ) external {
        uint256 tokensLength = tokens.length;
        if (tokensLength == 0) {
            revert NoTokensProvided();
        }

        for (uint256 i = 0; i < tokensLength; ++i) {
            if (tokens[i] == address(0)) {
                revert ZeroToken();
            }
            // Set infinite allowance (type(uint256).max) regardless of current allowance
            IERC20(tokens[i]).forceApprove(PERMIT3, type(uint256).max);
        }
    }
}


Vulnerability type: CWE-284|CWE-285|CWE-862
HIGH severity: External interface IPessimisticVeloLpOracle is outdated. The `IPessimisticVeloLpOracle` interface defines a function `getCurrentPoolPrice`, but the actual implementation at the provided address uses `getCurrentPrice`, making the two incompatible. This mismatch causes any call to `_getPriceValue` through the interface to revert, breaking functionality in d...

Vulnerable code:
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;

interface IPessimisticVeloLpOracle {
  function getCurrentPoolPrice(address _pool) external view returns (uint256 _price);
}

// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.20;

import {IBaseOracle} from '@interfaces/oracles/IBaseOracle.sol';

import {IBeefyVeloVaultRelayer} from '@interfaces/oracles/IBeefyVeloVaultRelayer.sol';

import {IBeefyVaultV7} from '@interfaces/external/IBeefyVaultV7.sol';
import {IVeloPool} from '@interfaces/external/IVeloPool.sol';
import {IPessimisticVeloLpOracle} from '@interfaces/external/IPessimisticVeloLpOracle.sol';

import {Math, WAD} from '@libraries/Math.sol';

import {AbstractVeloVaultRelayer} from './AbstractVeloVaultRelayer.sol';

/**
 * @title  BeefyVeloVaultRelayer
 * @notice Deconstructs a Beefy Vault to it's Velodrome liquidity pool and that pool's constituent tokens to return a price feed
 * @dev  Requires an underlying Velodrome pool and price feeds for the pool's tokens
 */
contract BeefyVeloVaultRelayer is AbstractVeloVaultRelayer, IBeefyVeloVaultRelayer {
  using Math for uint256;

  // --- Registry ---
  /// @inheritdoc IBeefyVeloVaultRelayer
  IBeefyVaultV7 public beefyVault;

  // --- Init ---

  /**
   *
   * @param  _beefyVault The address of the beefy vault contract
   * @param  _veloPool The address of the velo pool underlying the beefy vault
   * @param _veloLpOracle The address of the pessimistic velo lp oracle
   */
  constructor(
    IBeefyVaultV7 _beefyVault,
    IVeloPool _veloPool,
    IPessimisticVeloLpOracle _veloLpOracle
  ) AbstractVeloVaultRelayer(_veloPool, _veloLpOracle, string(abi.encodePacked(_beefyVault.symbol(), ' / USD'))) {
    if (address(_beefyVault) == address(0)) {
      revert BeefyVeloVaultRelayer_NullBeefyVault();
    }

    beefyVault = _beefyVault;
  }

  /// @notice Returns the price of the moo token
  function _getPriceValue() internal view override returns (uint256 _combinedPriceValue) {
    // 1 mooToken
    uint256 _mooTokenBalance = 1_000_000_000_000_000_000;

    // # of velo LP tokens in 1 mooToken
    uint256 _veloLpBalance = _mooTokenBalance.wmul(beefyVault.getPricePerFullShare());

    // price of 1 velo LP token in chainlink price decimals (8)
    uint256 _veloLpPrice = veloLpOracle.getCurrentPoolPrice(address(veloPool));

    return (_veloLpBalance * _veloLpPrice) / 1e8;
  }
}


Vulnerability type: CWE-710|CWE-684|CWE-440
HIGH severity: Overflow in quantize Function Can Cause a DoS. The vulnerability exists in the `quantize` function where an intermediate overflow occurs during the calculation due to the operation `2 ** offset` when `offset = 256`. This causes the entire expression to revert because Solidity performs arithmetic operations sequentially, and the overflow happens...

Vulnerable code:
// SPDX-License-Identifier: GNU General Public License Version 3
// See license at: https://github.com/forta-network/forta-firewall-contracts/blob/master/LICENSE-GPLv3.md

pragma solidity ^0.8.25;

import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";

/**
 * @notice Until the attestation can arrive on chain and the user transaction can be executed,
 * the asset amounts that will be processed can fluctuate slightly and cause different hashes
 * to be produced during the real execution and a mismatch with the values in the attestation.
 * This library solves this problem by quantizing the reference value used in checkpoint hash
 * computation.
 */
library Quantization {
    /**
     * @notice Quantizes the given value by zeroing the smaller digits.
     * @param n Input value.
     */
    function quantize(uint256 n) public pure returns (uint256) {
        uint256 offset = 8 * Math.log256(n);
        return ((n >> offset) << offset) + (2 ** offset) - 1;
    }
}


Vulnerability type: CWE-682|CWE-190
HIGH severity: Potential Signature Replay Attack in ERC1271Handler. The `isValidSignature` function in the `ERC1271Handler` contract lacks sufficient validation to prevent signature replay attacks. For EOA signatures, the function only verifies the signature's validity and its association with a `k1owner`, without imposing restrictions on how the hash is constructed...

Vulnerable code:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

import { IERC1271Upgradeable } from "@openzeppelin/contracts-upgradeable/interfaces/IERC1271Upgradeable.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";

import { SignatureDecoder } from "../libraries/SignatureDecoder.sol";
import { IModuleValidator } from "../interfaces/IModuleValidator.sol";
import { OwnerManager } from "../managers/OwnerManager.sol";
import { ValidatorManager } from "../managers/ValidatorManager.sol";

/// @title ERC1271Handler
/// @author Matter Labs
/// @notice Contract which provides ERC1271 signature validation
/// @notice The implementation is inspired by Clave wallet.
abstract contract ERC1271Handler is IERC1271Upgradeable, OwnerManager, ValidatorManager {
  bytes4 private constant _ERC1271_MAGIC = 0x1626ba7e;

  /**
   * @dev Should return whether the signature provided is valid for the provided data. Does not run validation hooks.
   * @param hash bytes32 - Hash of the data that is signed
   * @param signature bytes calldata - K1 owner signature OR validator address concatenated to signature
   * @return magicValue bytes4 - Magic value if the signature is valid, 0 otherwise
   */
  function isValidSignature(bytes32 hash, bytes memory signature) external view override returns (bytes4 magicValue) {
    if (signature.length == 65) {
      (address signer, ECDSA.RecoverError err) = ECDSA.tryRecover(hash, signature);
      return
        signer == address(0) || err != ECDSA.RecoverError.NoError || !_isK1Owner(signer) ? bytes4(0) : _ERC1271_MAGIC;
    }

    (bytes memory decodedSignature, address validator) = SignatureDecoder.decodeSignatureNoHookData(signature);

    bool isValid = _isModuleValidator(validator) &&
      IModuleValidator(validator).validateSignature(hash, decodedSignature);

    magicValue = isValid ? _ERC1271_MAGIC : bytes4(0);
  }
}


Vulnerability type: CWE-693|CWE-345|CWE-347
HIGH severity: Storage Slot Collision with Clave Protocol. The `SsoStorage` library uses a storage slot that is identical to one used by the Clave protocol, which could lead to storage collisions if both protocols are deployed in the same environment or if future upgrades are not carefully managed. This occurs because the storage slot was derived from a has...

Vulnerable code:
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.24;

import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";

library SsoStorage {
  bytes32 private constant SSO_STORAGE_SLOT = 0x3248da1aeae8bd923cbf26901dc4bfc6bb48bb0fbc5b6102f1151fe7012884f4;

  struct Layout {
    // ┌───────────────────┐
    // │   Ownership Data  │
    EnumerableSet.AddressSet k1Owners;
    uint256[50] __gap_0;
    // └───────────────────┘

    // ┌───────────────────┐
    // │     Validation    │
    EnumerableSet.AddressSet moduleValidators;
    uint256[50] __gap_2;
    // └───────────────────┘

    // ┌───────────────────┐
    // │       Hooks       │
    EnumerableSet.AddressSet validationHooks;
    EnumerableSet.AddressSet executionHooks;
    uint256[50] __gap_4;
    // └───────────────────┘
  }

  function layout() internal pure returns (Layout storage l) {
    bytes32 slot = SSO_STORAGE_SLOT;
    assembly {
      l.slot := slot
    }
  }
}


Vulnerability type: CWE-693
MEDIUM severity: Hooks Do Not Receive All Relevant Data. The hook system in the contract, designed to allow fine-grained validation logic, fails to pass critical execution data to certain hook functions. Specifically, the `handleAfterValidateUserOp` function does not receive the `validationData` parameter, which contains `validAfter`, `validUntil`, and `s...

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

import {PackedUserOperation} from "account-abstraction/interfaces/PackedUserOperation.sol";

/// @title IValidationHook
/// @notice Hook interface for optional signature validation logic
/// @dev The keyHash is validated against the signature before each hook is called, but
///      the hookData is NOT signed over or validated within the account. It MUST be treated as unsafe and can be set by anybody.
interface IValidationHook {
    /// @notice Hook called after `validateUserOp` is called on the account by the entrypoint
    /// @param keyHash the key which signed over userOpHash
    /// @param userOp UserOperation
    /// @param userOpHash hash of the UserOperation
    /// @param hookData any data to be passed to the hook. This has NOT been validated by the user signature
    /// @return selector Must be afterValidateUserOp.selector
    /// @dev The hook can revert to prevent the UserOperation from being validated.
    function afterValidateUserOp(
        bytes32 keyHash,
        PackedUserOperation calldata userOp,
        bytes32 userOpHash,
        bytes calldata hookData
    ) external view returns (bytes4 selector);

    /// @notice Hook called after verifying a signature over a digest in an EIP-1271 callback. 
    /// @dev MUST revert to signal that validation should fail
    /// @param keyHash the key which signed over digest
    /// @param digest the digest to verify
    /// @param hookData any data to be passed to the hook.This has NOT been validated by the user signature
    /// @return selector Must be afterIsValidSignature.selector
    function afterIsValidSignature(bytes32 keyHash, bytes32 digest, bytes calldata hookData)
        external
        view
        returns (bytes4 selector);

    /// @notice Hook called after verifying a signature over `SignedBatchedCall`. 
    /// @dev MUST revert to signal that validation should fail
    /// @param keyHash the key which signed over digest
    /// @param digest the digest to verify
    /// @param hookData any data to be passed to the hook. This has NOT been validated by the user signature
    /// @return selector Must be afterVerifySignature.selector
    function afterVerifySignature(bytes32 keyHash, bytes32 digest, bytes calldata hookData)
        external
        view
        returns (bytes4 selector);
}


Vulnerability type: CWE-664|CWE-221|CWE-223
HIGH severity: Potential Malformed Calldata. The `removeSelector` function in `CalldataDecoder.sol` performs an unchecked subtraction of 4 from `data.length` in inline assembly without verifying that the input calldata is at least 4 bytes long. If a shorter input is provided, this operation will underflow, resulting in a large, invalid length...

Vulnerable code:
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.23;

/// @title CalldataDecoder
library CalldataDecoder {
    /// @notice Removes the selector from the calldata and returns the encoded params.
    function removeSelector(bytes calldata data) internal pure returns (bytes calldata params) {
        assembly {
            params.offset := add(data.offset, 4)
            params.length := sub(data.length, 4)
        }
    }
}


Vulnerability type: CWE-682|CWE-191