69769 sc low setmigrationpermit prevents users from revoking migration consent after migrator role is revoked

Submitted on Mar 16th 2026 at 18:12:11 UTC by @PotEater for Audit Comp | Folks Finance: Staking Contracts

  • Report ID: #69769

  • 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

The function setMigrationPermit checks that the migrator address holds the MIGRATOR_ROLE every time. This is problematic, when a migrator's role is revoked, any user who previously granted that migrator permission becomes permanently unable to revoke it.

Vulnerability Details

In the Staking.sol contract, the function setMigrationPermit allows users to grant a migrator permit to migrator:

function setMigrationPermit(address _migrator, bool _isMigrationPermitted) external {
    if (!hasRole(MIGRATOR_ROLE, _migrator)) revert MigratorNotFound(_migrator);

    migrationPermits[_migrator][msg.sender] = _isMigrationPermitted;
    emit MigrationPermitUpdated(_migrator, msg.sender, _isMigrationPermitted);
}

However this function applies the hasRole check regardless of whether the user is granting or revoking.

When the migrator role has been revoked from the migrator, the call reverts with MigratorNotFound error, leaving the permit stuck at true until the migrator gets the MIGRATOR_ROLE again.

The contract promises users to be able to manage their own migration permits via this function. However, this promise is broken in the following scenario:

  1. User calls setMigrationPermit(migrator, true), granting a permit.

  2. Admin revokes migrator role.

  3. User calls setMigrationPermit(migrator, false), but tx reverts with MigratorNotFound.

  4. User permit is stuck at true until the migrator acquires the MIGRATOR_ROLE again.

NOTE: This isnt a known issue, as the issue in the known issues section acknowledges the fact that the migrator role permits in storage:

State “migrationPermits” may contain migrator which had its MIGRATOR_ROLE later revoked

This report is about users not being able to revoke the permit from the migrator and the migrator later reacquiring the MIGRATOR_ROLE and migrate users position without their current consent. This issue differs because fixing the known issue will not fix this one.

Impact Details

Smart contract fails to deliver promised returns - The contract promises users to be able to revoke the migrator permit at any time. However, this promise is broken when the MIGRATOR_ROLE is revoked from the migrator. The user has no way to revoke the migrator permit and the migrator can later regain his role and migrate user position without his consent.

This can also severely disrupt users financial plans.

References

Root cause: https://github.com/Folks-Finance/folks-staking-contracts/blob/3131a2d46b5afa76f606bf08adfd85452a47e2d8/src/Staking.sol#L78

Proof of Concept

Add this function to the Staking.t.sol file:

For this test to run you may need to import:

Run with forge test --match-test test_PoC -vvvv

Was this helpful?