57300 sc insight initialization bypasses the max 2 weeks guard for min upgrade delay
Submitted on Oct 25th 2025 at 04:39:57 UTC by @Afriauditor for Audit Comp | Folks Finance: Wormhole NTT on Algorand
Report ID: #57300
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/Folks-Finance/algorand-ntt-contracts/blob/main/ntt_contracts/ntt_manager/NttManager.py
Impacts: Contract fails to deliver promised returns, but doesn't lose value
Description
Brief / Intro
NttManager.py inherits the Upgradeable contract. In Upgradeable, admins are constrained to set a maximum minimum-upgrade delay of two weeks enforced in the setter via:
assert min_upgrade_delay <= self.max_for_min_upgrade_delay(), "Delay exceeds maximum allowed"
The code comments explicitly state this cap “prevents setting get_active_min_upgrade_delay() so large that upgrades become effectively impossible.” However, this constraint is not enforced at initialization: NttManager.create(...) forwards the provided min_upgrade_delay to Upgradeable.create(...), which does not validate the value. As a result, an arbitrarily large delay can be locked in at genesis.
Vulnerability Details
NttManager.create(..., min_upgrade_delay)→ callsUpgradeable.create(self, min_upgrade_delay).Upgradeable.create(min_upgrade_delay)storesdelay_1 = min_upgrade_delaywithout the two-week cap check.All future scheduling operations must satisfy:
timestamp >= Global.latest_timestamp + get_active_min_upgrade_delay()
If the initial
min_upgrade_delayis set to an extremely large value at creation, the system effectively prevents timely scheduling of:contract upgrades, and
future reductions to the delay itself,
contradicting the safety intent documented in the code.
Impact Details
A large min_upgrade_delay at deployment effectively locks the contract’s upgrade path.
References
Target source: https://github.com/Folks-Finance/algorand-ntt-contracts/blob/main/ntt_contracts/ntt_manager/NttManager.py
Proof of Concept
Add the following test to NttManger.test.ts to demonstrate that create accepts a delay greater than two weeks and stores it unbounded:
test("create uses provided min_upgrade_delay even if > 2 weeks", async () => {
const HUGE_DELAY = 20n * SECONDS_IN_DAY; // set to 20 days which is over over 2 weeks
const { appClient } = await factory.deploy({
createParams: {
sender: creator,
method: "create",
args: [nttTokenAppId, SOURCE_CHAIN_ID, THRESHOLD, HUGE_DELAY],
extraFee: (1000).microAlgos(),
},
});
// read this instance's state
expect(await appClient.state.global.minUpgradeDelay()).toEqual({
delay_0: 0n,
delay_1: HUGE_DELAY, // proves no clamp at create-time
timestamp: 0n,
});
expect(await appClient.getActiveMinUpgradeDelay()).toEqual(HUGE_DELAY);
});Notes
No fixes or mitigation steps are included in this report.
Was this helpful?