69898 sc low stale migration approvals allow a re authorized migrator to move user positions without renewed consent

Submitted on Mar 17th 2026 at 10:48:53 UTC by @IronsideSec for Audit Comp | Folks Finance: Staking Contracts

  • Report ID: #69898

  • Report Type: Smart Contract

  • Report severity: Low

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

  • Impacts:

    • Contract fails to deliver promised returns, but doesn't lose value

Description

Brief/Intro

setMigrationPermit() only allows users to update permissions for addresses that currently hold MIGRATOR_ROLE. If a migrator was previously approved, then loses the role, the old approval remains stored and the user can no longer revoke it. If the same address later receives MIGRATOR_ROLE again, it immediately regains the ability to migrate that user's positions without fresh consent.

Vulnerability Details

The bug is caused by the mismatch between permission storage and permission revocation rules. setMigrationPermit() reverts when _migrator does not currently hold MIGRATOR_ROLE, but migrationPermits[_migrator][user] is not cleared when the role is revoked. As a result, a stale true value can survive role removal and become active again after the role is regranted.

  • Alice calls setMigrationPermit(migrator, true).

  • The admin revokes MIGRATOR_ROLE from migrator.

  • Alice then tries to revoke the approval with setMigrationPermit(migrator, false), but the call reverts with MigratorNotFound, so the stored approval stays true.

  • The admin grants MIGRATOR_ROLE back to the same address.

  • The migrator can now call migratePositionsFrom(alice) successfully and receive 10 ether + 3,170,979,198,376 wei (check poc), even though Alice attempted to revoke approval before the role was restored.

This proves the approval is not truly revocable once the role is removed, and that old consent can be resurrected later by admin action.

Impact Details

Contract fails to deliver promised returns, but doesn't lose value :

This is a broken authorization / stale permission issue. A previously approved migrator can regain migration power over users without those users providing fresh consent. In the PoC, the migrator is able to pull Alice's full live position worth 10.000003170979198376 tokens. In production, the impact scales to the sum of all still-open positions and reserved rewards belonging to users who once approved that migrator address and were later unable to revoke it after role removal.

References

https://github.com/Folks-Finance/folks-staking-contracts/blob/3131a2d46b5afa76f606bf08adfd85452a47e2d8/src/Staking.sol#L77-L83

Proof of Concept

Paste into test/staking.t.sol.

Was this helpful?