Platform: Code4rena
Start Date: 01/08/2022
Pot Size: $50,000 USDC
Total HM: 26
Participants: 133
Period: 5 days
Judge: Jack the Pug
Total Solo HM: 6
Id: 151
League: ETH
Rank: 16/133
Findings: 4
Award: $844.44
🌟 Selected for report: 1
🚀 Solo Findings: 0
94.8726 USDC - $94.87
https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L386 https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L330-L359
When Project.setComplete()
is called , the task status is updated to Complete
and task cost transferred to subcontractor . However it is possible for anyone to set the Task status for the same task back to Active
then call Project.setComplete() again and repeat until remaining funds in project are drained.
Above is possible when the signature is forged or a signature replay after changing to a new subcontractor by calling changeOrder() then accepting the invitation by calling acceptInviteSC() . The former action will set TaskStatus
to Inactive , and the latter would set TaskStatus
to Active allowing the new subcontractor to call setComplete() and receive funds.
The process can be repeated until the funds lent to the project are drained.
Additionally, it is possible for the contractor to steal funds from the project after a setComplete() by approving a second address in approveHash(keccak256(data)
(data param to be used in changeOrder call). Contract then makes the changeOrder() call after approving the hash, and the check would pass when it jumps to checkSignatureTask()
due to the OR operation.
Complete
.approvedHashes
mapping.changeOrder()
with the crafted params in no.4 and she is able to pass the signature checks.InActive
.Active
Manual review
The Task state should not be changed once it is Completed.
#0 - horsefacts
2022-08-06T21:23:03Z
423.254 USDC - $423.25
https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L887 https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L108-L115
It is possible to pass Signature Validity check with an SignatureDecoder.recoverKey() returns 0 whenever the builder and /or contractor have an existing approved hash for a data.
With occurrence of above, any user can call changeOrder or setComplete functions successfully after user approves data hashes.
Manual review
There should be a require check for _recoveredSignature != 0
in checkSignatureValidity()
#0 - parv3213
2022-08-17T06:28:14Z
#1 - jack-the-pug
2022-08-27T09:50:03Z
Making this the main issue.
285.6964 USDC - $285.70
https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Disputes.sol#L74-L81
Signature checks in project.sol can be bypassed for AddTask(), orderChange() and setComplete() functions when the caller of the functions is the Disputes.sol contract
The Disputes.initialize() function can be frontrunned by any user can and set their arbitrary homeFi contract.This would allow the arbitrary contract admin to resolve disputes and bypass signature checks in the 3 functions above in Project.sol contract.
One major impact is that a subcontractor can keep receiving funds for the same task multiple times by going through the process above bypassing the signature check section in Project.setComplete()
if (_msgSender() != disputes) { // Check signatures. checkSignatureTask(_data, _signature, _taskID); }
Manual review
There should be an access control on the initialize() function to ensure it is called only by contract owner or contract deployer.
#0 - 0xA5DF
2022-08-12T08:58:32Z
Subset of #6
#1 - jack-the-pug
2022-08-27T05:12:13Z
Duplicate of #6
🌟 Selected for report: Lambda
Also found by: 0x1f8b, 0x52, 0xA5DF, 0xNazgul, 0xNineDec, 0xSmartContract, 0xSolus, 0xf15ers, 0xkatana, 0xsolstars, 8olidity, Aymen0909, Bahurum, Bnke0x0, CertoraInc, Chom, CodingNameKiki, Deivitto, Dravee, ElKu, Extropy, Funen, GalloDaSballo, Guardian, IllIllI, JC, Jujic, MEP, Noah3o6, ReyAdmirado, Rohan16, Rolezn, Ruhum, Sm4rty, SooYa, Soosh, Throne6g, TomJ, Tomio, TrungOre, Waze, Yiko, _Adam, __141345__, a12jmx, ajtra, ak1, arcoun, asutorufos, ayeslick, benbaessler, berndartmueller, bin2chen, bobirichman, brgltd, bulej93, byndooa, c3phas, codexploder, cryptonue, cryptphi, defsec, delfin454000, dipp, djxploit, erictee, exd0tpy, fatherOfBlocks, gogo, hake, hansfriese, horsefacts, hyh, ignacio, indijanc, joestakey, kaden, mics, minhquanym, neumo, obront, oyc_109, p_crypt0, pfapostol, poirots, rbserver, robee, rokinot, rotcivegaf, sach1r0, saian, samruna, saneryee, scaraven, sikorico, simon135, sseefried, supernova
40.621 USDC - $40.62
https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L330 https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L386 https://github.com/code-423n4/2022-08-rigor/blob/main/contracts/Project.sol#L219
There are 3 instances where a check for ongoing dispute should have been done at the start of the functions, however there were no such checks.
Using setComplete as an example, it was documented in contest page .... If there is no ongoing dispute about that project, task status is updated and payment is made....
, looking at the code, when a TaskPay actionType dispute has been raised for a Task on the project, setComplete() can still be called successfully.
Above is similar to the orderChange() and addTask() functions.
Manual review
A check for dispute present should be done at the start of the function calls for addTask, orderChange and setComplete functions.