#48990 [SC-Low] Integer underflow in remove_item leads to AVM trap and DoS via empty array call
Submitted on Jul 10th 2025 at 09:20:14 UTC by @Bug82427 for Audit Comp | Folks Smart Contract Library
Report ID: #48990
Report Type: Smart Contract
Report severity: Low
Target: https://github.com/Folks-Finance/algorand-smart-contract-library/blob/main/contracts/library/UInt64SetLib.py
Impacts:
Impacts caused by griefing with no economic damage other than transaction fees where fix requires a change or a pause of a smart contract
Description
Brief/Intro The remove_item function in the UInt64SetLib library is vulnerable to an integer underflow when called with an empty array. The line last_idx = items.length - 1 causes a wraparound on subtraction when the array is empty, resulting in a hard trap in the Algorand Virtual Machine (AVM). This causes the entire transaction to fail and introduces a vector for griefing or denial-of-service (DoS) when invoked without proper guards.
Vulnerability Details The vulnerability lies in this line:
python
last_idx = items.length - 1
This operation assumes that items.length is at least 1. However, if the input array is empty, this becomes 0 - 1, which underflows in the UInt64 domain and wraps to 2^64 - 1. This triggers a trap on AVM execution due to an invalid operation.
There is no input validation or precondition that ensures the array is non-empty. Thus, any contract that uses this library function without additional validation becomes vulnerable to a full halt in execution.
This violates both defensive programming practices and safe library behavior expected in reusable utility modules.
References CWE-191: Integer Underflow (Wrap or Wraparound) — https://cwe.mitre.org/data/definitions/191.html
Proof of Concept
Step-by-step PoC Instantiate an empty DynamicArray[ARC4UInt64]:
python
items = DynamicArrayARC4UInt64 Call the vulnerable function:
python remove_item(UInt64(123), items) Inside remove_item, the following line executes:
python
last_idx = items.length - 1 # 0 - 1 = underflow This results in:
python
last_idx = UInt64(2^64 - 1) AVM traps execution, crashing the transaction entirely. No error is recoverable.
This can be triggered even with benign input and becomes dangerous in multi-step contract flows, as it halts any downstream execution logic.
Remediation Add a simple guard clause at the beginning of remove_item:
python
if items.length == 0: return Bool(False), items.copy() This prevents the invalid subtraction and ensures safe use even in edge cases. It also maintains consistent return types.
Was this helpful?