The bug is arises from attempting to access locked token data for a player when data does not exist. Specifically, that the function does not check if the player has locked tokens for each configured token contract before attempting to access the data here is the vulnerable part :
This function is called to retrieve the locked tokens for a player. and If the player has no locked tokens, the function should return default values rather than causing an error. and impacts users' ability to query their locked tokens correctly.
Impact
The getLocked function fails to handle cases where a player has no locked tokens for some or all configured token contracts and rhis results in a KeyError, causing the function to revert and fail. This impact users who query their locked tokens and receive an error instead of the expected result.
Proof of Concept
Detailed Scenario show the issue:
A player with no locked tokens calls the getLocked function.
The function attempts to access lockedTokens[_player][configuredTokenContracts[i]] without checking if the player has locked tokens for the token contract at index i.
and this results in a KeyError, causing the function to revert and fail.
let's say we assume taht the player 0xPlayerAddress calls getLocked with configuredTokenContracts containing ['0xToken1', '0xToken2'],
but lockedTokens for 0xPlayerAddress is an empty dictionary ({}).
so The function will try to access lockedTokens['0xPlayerAddress']['0xToken1'] which does not exist, and this leading to a KeyError.
here is the test :
def getLocked(_player, configuredTokenContracts, lockedTokens):
configuredTokensLength = len(configuredTokenContracts)
tmpLockedTokens = [None] * configuredTokensLength
for i in range(configuredTokensLength):
if configuredTokenContracts[i] in lockedTokens[_player]:
tmpLockedToken = LockedToken(
lockedTokens[_player][configuredTokenContracts[i]].unlockTime,
lockedTokens[_player][configuredTokenContracts[i]].quantity,
lockedTokens[_player][configuredTokenContracts[i]].lastLockTime,
lockedTokens[_player][configuredTokenContracts[i]].remainder
)
else:
tmpLockedToken = LockedToken(0, 0, 0, 0)
tmpLockedTokens[i] = LockedTokenWithMetadata(tmpLockedToken, configuredTokenContracts[i])
return tmpLockedTokens
here Player with No Locked Tokens
# Test data
lockedTokens_empty = {
'0xPlayerAddress': {}
}
# the simulation
lockedTokensResult_empty = getLocked(player, configuredTokenContracts, lockedTokens_empty)
results_empty = []
for token in lockedTokensResult_empty:
results_empty.append((token.tokenContract, token.lockedToken.unlockTime, token.lockedToken.quantity, token.lockedToken.lastLockTime, token.lockedToken.remainder))
results_empty
here Player with Edge Case Values
# Test data
lockedTokens_edge = {
'0xPlayerAddress': {
'0xToken1': LockedToken(2**32 - 1, 2**256 - 1, 2**32 - 1, 2**256 - 1)
}
}
# the simulation
lockedTokensResult_edge = getLocked(player, configuredTokenContracts, lockedTokens_edge)
results_edge = []
for token in lockedTokensResult_edge:
results_edge.append((token.tokenContract, token.lockedToken.unlockTime, token.lockedToken.quantity, token.lockedToken.lastLockTime, token.lockedToken.remainder))
results_edge
here where is Invalid Token Addresses
# Test data
configuredTokenContracts_invalid = ['0xInvalidToken']
lockedTokens_invalid = {
'0xPlayerAddress': {
'0xInvalidToken': LockedToken(100, 50, 75, 5)
}
}
# the simulation
lockedTokensResult_invalid = getLocked(player, configuredTokenContracts_invalid, lockedTokens_invalid)
results_invalid = []
for token in lockedTokensResult_invalid:
results_invalid.append((token.tokenContract, token.lockedToken.unlockTime, token.lockedToken.quantity, token.lockedToken.lastLockTime, token.lockedToken.remainder))
results_invalid
Tools Used
manual review
Recommended Mitigation Steps
need a check to handle cases where the player has no locked tokens
Lines of code
https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L440-L442
Vulnerability details
Vulnerability Details
The bug is arises from attempting to access locked token data for a player when data does not exist. Specifically, that the function does not check if the player has locked tokens for each configured token contract before attempting to access the data here is the vulnerable part :
This function is called to retrieve the locked tokens for a player. and If the player has no locked tokens, the function should return default values rather than causing an error. and impacts users' ability to query their locked tokens correctly.
Impact
The getLocked function fails to handle cases where a player has no locked tokens for some or all configured token contracts and rhis results in a KeyError, causing the function to revert and fail. This impact users who query their locked tokens and receive an error instead of the expected result.
Proof of Concept
Detailed Scenario show the issue:
here is the test :
here Player with No Locked Tokens
here Player with Edge Case Values
here where is Invalid Token Addresses
Tools Used
manual review
Recommended Mitigation Steps
need a check to handle cases where the player has no locked tokens
Assessed type
Other