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:
User calls
setMigrationPermit(migrator, true), granting a permit.Admin revokes migrator role.
User calls
setMigrationPermit(migrator, false), but tx reverts withMigratorNotFound.User permit is stuck at
trueuntil the migrator acquires theMIGRATOR_ROLEagain.
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?