#46721 [SC-Insight] Inconsistencies for agentTimelockedOperationWindowSeconds value checks between SettingsInitializer.sol::_validateSettings and SettingsManagementFacet.sol::setAgentTimelockedOpera...
Submitted on Jun 3rd 2025 at 23:18:22 UTC by @hunter0xweb3 for Audit Comp | Flare | FAssets
Report ID: #46721
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/flare-foundation/fassets/blob/main/contracts/assetManager/library/SettingsInitializer.sol
Impacts:
Contract fails to deliver promised returns, but doesn't lose value
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)
Description
Brief/Intro
There is an inconsistency between requirements check for minimum value for agentTimelockedOperationWindowSeconds in SettingsInitializer.sol::_validateSettings and SettingsManagementFacet.sol::setAgentTimelockedOperationWindowSeconds functions leading to protocol invariant conditionals breakage as shown below
Vulnerability Details
Protocol defines settings.agentTimelockedOperationWindowSeconds variable to set the time window for agent's validity actions.
Ie once an agent action can be executed (after action was anounced and wait period has passed), agent has settings.agentTimelockedOperationWindowSeconds time to execute it before action ability to execute expires: Take for example and agent trying to exit (after exit announcement): It has settings.agentTimelockedOperationWindowSeconds to execute exit action as checked in [1]: https://github.com/flare-labs-ltd/fassets/blob/acb82a27b15c56ce9dfbb6dbbd76008da6753c26/contracts/assetManager/library/AvailableAgents.sol#L73
function exit(
address _agentVault
)
internal
onlyAgentVaultOwner(_agentVault)
{
//......
Agent.State storage agent = Agent.get(_agentVault);
require(agent.availableAgentsPos != 0, "agent not available");
require(agent.exitAvailableAfterTs != 0, "exit not announced");
require(block.timestamp >= agent.exitAvailableAfterTs, "exit too soon");
[1]> require(block.timestamp <= agent.exitAvailableAfterTs + settings.agentTimelockedOperationWindowSeconds,
"exit too late");
Or while withdrawing tokens same variable is checked: https://github.com/flare-labs-ltd/fassets/blob/acb82a27b15c56ce9dfbb6dbbd76008da6753c26/contracts/assetManager/library/AgentsExternal.sol#L124
function beforeCollateralWithdrawal(
IERC20 _token,
address _agentVault,
uint256 _amountWei
)
internal
{
Agent.State storage agent = Agent.get(_agentVault);
Collateral.Kind kind;
//...
@> require(block.timestamp <= withdrawal.allowedAt + settings.agentTimelockedOperationWindowSeconds,
"withdrawal: too late");
The issue occurs because there are inconsistencies between checks when setting settings.agentTimelockedOperationWindowSeconds value.
contracts/assetManager/library/SettingsInitializer.sol::_validateSettings checks that agents has at least one hour as a time window to execute its announced action: This checks are performed on settings initialization, ie global settings set up: https://github.com/flare-labs-ltd/fassets/blob/acb82a27b15c56ce9dfbb6dbbd76008da6753c26/contracts/assetManager/library/SettingsInitializer.sol#L41
function _validateSettings(
AssetManagerSettings.Data memory _settings
)
private pure
{
require(_settings.fAsset != address(0), "zero fAsset address");
require(_settings.agentVaultFactory != address(0), "zero agentVaultFactory address");
//...
//...
@> require(_settings.agentTimelockedOperationWindowSeconds >= 1 hours, "value too small");
However contracts/assetManager/facets/SettingsManagementFacet.sol allows to set settings.agentTimelockedOperationWindowSeconds value as low as 1 minute: https://github.com/flare-labs-ltd/fassets/blob/acb82a27b15c56ce9dfbb6dbbd76008da6753c26/contracts/assetManager/facets/SettingsManagementFacet.sol#L557-L566
function setAgentTimelockedOperationWindowSeconds(uint256 _value)
external
onlyAssetManagerController
rateLimited
{
AssetManagerSettings.Data storage settings = Globals.getSettings();
// validate
@> require(_value >= 1 minutes, "value too small");
// update
settings.agentTimelockedOperationWindowSeconds = _value.toUint64();
emit SettingChanged("agentTimelockedOperationWindowSeconds", _value);
}
Leading to a really reduced time action window for agents making agents unable to perform anounced actions (DoS) and breaking the conditionals imposed on protocol settings initialization (settings.agentTimelockedOperationWindowSeconds value must be >= 1 hour)
Impact Details
Bypassing restriction and protocol settings initialization for settings.agentTimelockedOperationWindowSeconds (value must be >= 1 hour) DoS agents ability to execute action (exiting | withdrawing collateral) bypassing SettingsInitializer.sol::_validateSettings minimum value with SettingsManagementFacet.sol::setAgentTimelockedOperationWindowSeconds
References
https://github.com/flare-labs-ltd/fassets/blob/acb82a27b15c56ce9dfbb6dbbd76008da6753c26/contracts/assetManager/library/SettingsInitializer.sol#L41 https://github.com/flare-labs-ltd/fassets/blob/acb82a27b15c56ce9dfbb6dbbd76008da6753c26/contracts/assetManager/facets/SettingsManagementFacet.sol#L557-L566
Proof of Concept
Proof of Concept
Protocol is initiazed with settings.agentTimelockedOperationWindowSeconds = 1 hour (minimum accepted value) giving enough time for agents to execute actions (exit , withdraw, etc) Later SettingsManagementFacet.sol::setAgentTimelockedOperationWindowSeconds is used to set settings.agentTimelockedOperationWindowSeconds = 1 minute
Was this helpful?