53069 sc low dynamic cooldown interval changes cause unexpected fund lockup extensions
Submitted on Aug 14th 2025 at 18:51:13 UTC by @Outliers for Attackathon | Plume Network
Report ID: #53069
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/immunefi-team/attackathon-plume-network/blob/main/plume/src/facets/StakingFacet.sol
Impacts: Temporary freezing of funds for at least 24 hours
Description
Brief / Intro
Administrators can unexpectedly extend user cooldown periods by modifying the global cooldownInterval parameter between unstake transactions. Users who initiate unstaking with the expectation of a specific cooldown period (e.g., 7 days) can have their wait time arbitrarily extended (e.g., to 14 days) if an admin updates the cooldown interval before their subsequent unstake transaction executes. This violates user expectations and contradicts the protocol's documentation (https://docs.plume.org/plume/stake#important-notes-to-consider) which suggests a fixed 21-day unstake period, creating potential for griefing attacks and unpredictable fund access delays.
Vulnerability Details
The issue arises from the _processCooldownLogic function using the current global cooldownInterval value at transaction execution time, rather than preserving the cooldown period that was active when the user first initiated unstaking.
function _processCooldownLogic(
address user,
uint16 validatorId,
uint256 amount
) internal returns (uint256 newCooldownEndTime) {
// ... existing logic ...
// Uses CURRENT cooldownInterval, not the one from when user started unstaking
newCooldownEndTime = block.timestamp + $.cooldownInterval; // @audit - Admin can change this
if (currentCooledAmountInSlot > 0 && block.timestamp >= currentCooldownEndTimeInSlot) {
// Previous cooldown matured - start new cooldown with CURRENT interval
// ...
} else {
// Add to existing cooldown - but uses NEW cooldown end time
// ...
}
cooldownEntrySlot.cooldownEndTime = newCooldownEndTime; // Overwrites previous end time
}Attack consequences:
A user who expects a specific cooldown duration can be forced to wait longer if
cooldownIntervalchanges in between their unstake transactions.This allows griefing or denial-of-service-like scenarios where admins (or an attacker with admin control) can arbitrarily extend access to funds.
Attack Scenario
Impact Details
Users committed to shorter periods face unexpected extensions.
Protocol documentation and user expectations about fixed cooldown durations are violated.
Enables griefing via policy changes that are effectively retroactive for in-flight unstake flows.
Mitigation
Proof of Concept
// Initial setup
$.cooldownInterval = 7 days; // 604800 seconds
// Day 0: User first unstake
unstake(validatorId, 100e18); // at timestamp 1000
// cooldownEndTime = 1000 + 604800 = 1000 + 7 days
// User expects withdrawal at that time// Day 5: User submits second unstake transaction
// User calculates: expects new cooldown = 1005 + 7 days
uint256 userSubmissionTime = 1005;
// RACE CONDITION: Admin changes cooldown interval
// Admin transaction executes first:
$.cooldownInterval = 14 days; // 1209600 seconds// User transaction executes after admin change:
unstake(validatorId, 50e18); // at timestamp 1005
// _processCooldownLogic executes:
newCooldownEndTime = 1005 + $.cooldownInterval; // 1005 + 14 days
cooldownEntrySlot.cooldownEndTime = newCooldownEndTime; // OVERWRITES previous end time
// Result:
// User expected: 1005 + 7 days
// Actual result: 1005 + 14 days
// Additional delay: ~7 days beyond user expectationWas this helpful?