#36501 [SC-Medium] Signature Front-Running Vulnerability in CollateralVault

Submitted on Nov 4th 2024 at 13:24:08 UTC by @Hoverfly9132 for Audit Comp | Anvilarrow-up-right

  • Report ID: #36501

  • Report Type: Smart Contract

  • Report severity: Medium

  • Target: https://etherscan.io/address/0x5d2725fdE4d7Aa3388DA4519ac0449Cc031d675f

  • Impacts:

    • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Bug Description

The similar issue has found by the previous OpenZeppelin auditarrow-up-right but they don't specify all the affected actions, and anvil team only fix the `depositAndStake` function, the other affected actions aren't reported and fixed in the previous audits, so this issue shouldn't be considered as known issue from my perspective.

The `modifyCollateralizableTokenAllowanceWithSignature` function in CollateralVault is vulnerable to signature front-running attacks. When the `TimeBasedCollateralPool` contract `stake` and `stakeReleasableTokensFrom` functions call the `modifyCollateralizableTokenAllowanceWithSignature` function to modify the allowance by signature, an attacker can monitor the mempool and front-run the transaction by calling the `modifyCollateralizableTokenAllowanceWithSignature` function first, then the original transaction will fail because the nonce is already used.

The vulnerability exists because:

  1. The signature verification uses a nonce system that increments upon each use.

  2. The `modifyCollateralizableTokenAllowanceWithSignature` function can be called by anyone to cause the signature nonce to be incremented.

  3. Once a signature is used and the nonce is incremented, the original transaction will fail

Impact

Any users `stake` or `stakeReleasableTokensFrom` txs can be front-run by attackers to revert.

Recommendation

Fix as the `depositAndStake` function.

Proof of Concept

Proof of Concept

```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.19;

import "forge-std/Test.sol";

abstract contract EIP712 { bytes32 private immutable _CACHED_DOMAIN_SEPARATOR; uint256 private immutable _CACHED_CHAIN_ID;

}

abstract contract SignatureNonces { mapping(address => mapping(bytes32 => uint256)) private _accountTypeNonces;

}

contract CollateralVault is EIP712, SignatureNonces { bytes32 public constant COLLATERALIZABLE_TOKEN_ALLOWANCE_ADJUSTMENT_TYPEHASH = keccak256( "CollateralizableTokenAllowanceAdjustment(address collateralizableAddress,address tokenAddress,int256 allowanceAdjustment,uint256 approverNonce)" );

}

interface ICollateral { function modifyCollateralizableTokenAllowanceWithSignature( address _accountAddress, address _collateralizableContractAddress, address _tokenAddress, int256 _allowanceAdjustment, bytes calldata _signature ) external;

}

contract TimeBasedCollateralPool { ICollateral public immutable collateral; constructor(address _collateral) { collateral = ICollateral(_collateral); }

}

contract SignatureReplayTest is Test { CollateralVault public vault; address public victim; uint256 public victimPrivateKey; address public token; TimeBasedCollateralPool public pool;

} ```

Run the test by: ```bash forge test --match-test testFrontRunGriefing ```

Last updated

Was this helpful?