68906 sc insight missing reentrancy guard on function recovererc20

Submitted on Mar 11th 2026 at 21:53:23 UTC by @Afriauditor for Audit Comp | Folks Finance: Staking Contracts

  • Report ID: #68906

  • Report Type: Smart Contract

  • Report severity: Insight

  • Target: https://github.com/Folks-Finance/folks-staking-contracts/blob/main/src/Staking.sol

Description

Brief/Intro

The recoverERC20 function in Staking.sol lacks the nonReentrant modifier, unlike every other state-changing function that performs external token transfers (stake, stakeWithPermit, withdraw, migratePositionsFrom). When the manager recovers a non-staking ERC20 token that contains a transfer callback (e.g., ERC-777 tokens, or any malicious token with a hook), the receiving address can re-enter recoverERC20 before the first invocation completes.

Vulnerability Details

Every external function in Staking.sol that performs a token transfer is protected by nonReentrant — except recoverERC20. This function performs no state changes before calling safeTransfer, so if the recovered token has a transfer callback (ERC-777 or malicious hook), the receiving address can re-enter recoverERC20 repeatedly within a single transaction. For non-staking tokens the balance guard is skipped entirely, allowing full drain. For the staking token, the balanceOf check offers incidental protection, but this relies on the token decrementing its balance before the callback fires — an assumption that may not hold for all implementations. The manager does not need to be compromised; they simply need to recover a callback-enabled token, and the token itself becomes the attacker.

Impact Details

The absence of a nonReentrant modifier on recoverERC20 creates an inconsistent security posture that leaves the only admin-facing transfer function unprotected against the same reentrancy risk that every user-facing transfer function explicitly guards against.

Proof of Concept

Was this helpful?