Race condition in BuyerAgent.sol allows multiple transactions to process the same oracle request, leading to duplicate purchases and state updates.
The issue occurs in the following scenario:
A purchase/state update oracle request is made for a specific round
The request is processed once successfully
The same request can potentially be processed again in the same round
While the contract has the isOracleRequestProcessed mapping to prevent double processing:
contracts/swan/BuyerAgent.sol#L97: https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L97
The validation in purchase() and updateState() functions checks this flag: https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L206-L208
However, there's a race condition where
Multiple transactions could read isOracleRequestProcessed[taskId] as false
Process the same task
Before the mapping is updated to true
This could lead to:
Double execution of purchases
Duplicate state updates
Exceeding round spending limits
mapping contracts/swan/BuyerAgent.sol#https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L89-L97
The updateState contracts/swan/BuyerAgent.sol# https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L200-L216
The function purchase contracts/swan/BuyerAgent.sol# https://github.com/Cyfrin/2024-10-swan-dria/blob/c8686b199daadcef3161980022e12b66a5304f8e/contracts/swan/BuyerAgent.sol#L222-L255
The vulnerabilities create a race condition in oracle request processing. The non-atomic nature of the task completion checks and updates allows multiple transactions to process the same oracle request before the isProcessed flag is set.
Root Cause:
Non-atomic task processing allows multiple transactions to execute the same oracle request
Lack of synchronization between task completion check and state updates
Missing reentrancy protection on critical state changes
When we look at this example.
Double execution of purchase orders leading to excessive spending
Multiple state updates from single oracle responses
Potential violation of round spending limits
Vs
Implement atomic task processing using
Add a mutex lock during task processing
Use OpenZeppelin's ReentrancyGuard
Implement atomic task completion updates
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.