RockPaperScissors::commitMove
accepts any _commitHash
from players without any sanity checks.
The following is the attack path for a reused salt
1st turn
Player A commits a move using RockPaperScissors::commitMove
Player B commits a move using RockPaperScissors::commitMove
Player A reveals a move using RockPaperScissors::revealMove
. This reveals the salt used in step 1 for the first turn
Player B reveals a move using RockPaperScissors::revealMove
2nd turn
Player A commits a move using RockPaperScissors::commitMove
using the same salt as the 1st turn
Player B sees the player A's calldata in the mempool and uses the salt in the first turn to calculate the _commitHash
for each of the possible moves (Rock/Paper/Scissors), creating a hash table
Player B crosschecks the hash table with player A's 2nd turn _commitHash
to determine player A's move
Player B commits a winning move using RockPaperScissors::commitMove
Player A reveals a move using RockPaperScissors::revealMove
.
Player B reveals a move using RockPaperScissors::revealMove
Player B wins the 2nd turn
Place the following in RockPaperScissorsTest.t.sol
and run
forge test --mt testPredictReusedSalt
Impact: High, Player is able to predict the opponent's move and win, disrupting the fairness of the game
Likelihood: Medium, Opponent may not be aware that each turn requires a separate salt and reuses the previous round's salt
Severity: High
Manual review
Consider implementing the following:
RockPaperScissors::revealMove
should save the salt for each turn after it is revealed
RockPaperScissors::commitMove
checks if the player submitted _commitHash
uses any salts of the previous turns for each of the possible moves (Rock/Paper/Scissors) and reverts if a previous salt was used
The contract does not enforce salt uniqueness
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.