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

Submitted on Nov 4th 2024 at 13:24:08 UTC by @Hoverfly9132 for Audit Comp | Anvil

  • 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 audit 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?