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?