69747 sc low broken migration permit revocation allows stale user consent to reactivate after migrator role is re granted

Submitted on Mar 16th 2026 at 16:25:08 UTC by @SamuilKosev778857 for Audit Comp | Folks Finance: Staking Contracts

  • Report ID: #69747

  • 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 migration authorization flow contains a revocation flaw in setMigrationPermit(). A user can approve a migrator while it has MIGRATOR_ROLE, but if that role is later removed, the user can no longer revoke the previously granted approval because the function still requires the target address to currently hold MIGRATOR_ROLE even when the user is setting the permit to false.

Vulnerability Details

The issue is in the permit-setting logic:

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);
}

The problem is that the role check is unconditional. It is applied both when the user is granting permission and when the user is trying to revoke permission.

Impact Details

Users are given a per-migrator approval mechanism via setMigrationPermit(), which implies they can allow or deny migration authority for their own positions.

The practical consequences are:

  • users may believe they have revoked migration permission when they have not,

  • stale approvals can persist indefinitely,

  • migration authority can return later without fresh user consent.

References

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

Proof of Concept

Was this helpful?