Platform: Code4rena
Start Date: 03/02/2022
Pot Size: $75,000 USDC
Total HM: 42
Participants: 52
Period: 7 days
Judge: GalloDaSballo
Total Solo HM: 21
Id: 83
League: ETH
Rank: 10/52
Findings: 8
Award: $2,189.23
🌟 Selected for report: 3
🚀 Solo Findings: 1
🌟 Selected for report: mtz
Also found by: 0x1f8b, Czar102, GalloDaSballo, GeekyLumberjack, Randyyy, Rhynorater, Ruhum, ShadowyNoobDev, bitbopper, cccz, cmichel, csanuragjain, danb, gzeon, hickuphh3, hyh, leastwood
31.0722 USDC - $31.07
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/Shelter.sol#L52-L58
Shelter
has a function withdraw
that lets whitelisted users withdraw a specified amount of some token. The function does not check if the user has already withdrew the tokens. Since, a user can withdraw allowed amount any number of times, stealing all the funds.
Manual analysis
Add a check:
require(claimed[_token][msg.sender] == false, "already withdrew");
And change current:
claimed[_token][_to] = true;
to
claimed[_token][msg.sender] = true;
#0 - r2moon
2022-02-16T16:15:51Z
#1 - GalloDaSballo
2022-04-12T22:14:29Z
Duplicate of #246
🌟 Selected for report: Czar102
Also found by: harleythedog, hickuphh3, throttle
116.1295 USDC - $116.13
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L86-L101
Token fee in MasterChef
can be set to more than 100%, (for example by accident) causing all deposit
calls to fail due to underflow on subtraction when reward is lowered by the fee, thus breaking essential mechanics. Note that after the fee has been set to any value, it cannot be undone. A token cannot be removed, added, or added the second time. Thus, mistakenly (or deliberately, maliciously) added fee that is larger than 100% will make the contract impossible to recover from not being able to use the token.
Manual analysis
On setting fee ensure that it is below a set maximum, which is set to no more than 100%.
#0 - GalloDaSballo
2022-04-04T21:39:53Z
The warden has identified admin privilege that would enable them to set the deposit fee to 100% The value can also be increased above 100% to cause a denial of service to the user.
Mitigation would require offering a more appropriate upper limit to the fee
🌟 Selected for report: Czar102
1179.9976 USDC - $1,180.00
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L78-L80 https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L157-L180
Owner can steal Concur rewards by adding a depositor and inflating other depositors' assigned balance of the token within the contract. Thus, the owner-managed depositor can get most (all but one wei) of the created tokens.
Manual analysis
Do not allow the owner to add depositors after the depositors have been configured.
#0 - r2moon
2022-02-16T16:11:58Z
owner is a multisig & timelock. new depositors can be added later as well.
#1 - GalloDaSballo
2022-04-12T22:09:24Z
I think the warden could have done a better job at writing a POC.
That said the finding is valid, the sponsor could set a depositor
to be any EOA and because there's no transfer of tokens the balances could be inflated. Setting an immutable depositor would bring stronger security guarantees instead of allowing any contract to become a depositor.
Because this is contingent on admin privilege, I believe medium severity to be more appropriate
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L82-L84
Owner can remove a depositor. Since only depositors can deposit and withdraw, the owner may add a contract to the whitelist, let users deposit in the contarct and remove the depositor from the whitelist. Depositor's reward cannot be withdrawn then. And takes a share of Concur tokens that will not be ditributed.
Manual analysis
Remove onlyDepositor
modifier from the withdraw
function.
#0 - GalloDaSballo
2022-04-12T22:10:52Z
The finding is valid in that the sponsor / owner can remove all depositors.
I believe having an immutable depositor that can't be changed would give stronger security guarantees.
While the finding is valid, because it is contingent on a malicious owner, I believe Medium Severity to be more appropriate
🌟 Selected for report: leastwood
Also found by: CertoraInc, Czar102, WatchPug, csanuragjain, hickuphh3, kirk-baird
89.5856 USDC - $89.59
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L134-L154
The updatePool
function in MasterChef
is supposed to account for all blocks before endBlock
. But the if statement checks if the current block is after the deadline. Thus blocks between pool.lastRewardBlock
and endBlock
won't be accounted for iff block.number >= endBlock && endBlock > pool.lastRewardBlock
.
Additionally, the pendingConcur
function does not have the endBlock
functionality at all and this will lead to incorrect information given after the deadline.
Manual analysis
Check if the above condition holds, if yes, account for all blocks between pool.lastRewardBlock
and endBlock
.
To avoid dissociations of the values in the code, it is recommended to create a single function for such critical calculations and call it anytime the calculations are needed.
#0 - GalloDaSballo
2022-04-20T00:43:09Z
Dup of #107
🌟 Selected for report: ShadowyNoobDev
Also found by: 0xw4rd3n, CertoraInc, Czar102, GalloDaSballo, Heartless, IllIllI, Jujic, Randyyy, Rhynorater, Sleepy, SolidityScan, ckksec, kirk-baird, leastwood, pauliax, peritoflores, reassor
7.97 USDC - $7.97
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/ConcurRewardPool.sol#L34-L41
Any address that has nonzero reward for a token _tokens[i]
is able to drain all contact token funds if the transfer
function is reentrant (for example, ERC777 token). As _tokens[i]
is an arbitrarily implemented, a reentrant transfer
function can be assumed to be present among all _tokens
.
Let there be an address addr
that is a contarct and has its reward pushed on token token
that has a hookable transfer
function.
An exploiter created the addr
contract in a way that it hooked the transfer
function if tokens are sent to it from ConcurRewardPool
. Contract can be called to claimRewards
from ConcurRewardPool
with a list of length 1, consisting of token
. When a transfer occurs, the hook passes control back to the addr
, which can call claimRewards
again with the same argument and payout the same amount as reward[msg.sender][_tokens[i]]
asn't been yet modified.
Manual analysis
Swap lines 37 and 38 in the claimRewards
implementation.
#0 - r2moon
2022-02-16T16:38:23Z
duplicated with https://github.com/code-423n4/2022-02-concur-findings/issues/260
#1 - GalloDaSballo
2022-04-17T16:16:44Z
Duplicate of #86
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L201-L211
All calculations are rounded down, since a lack of tokens in the contracts cannot be rounding errors' fault. So the function is redundant.
On the other hand, if the contract is undersupplied with Concur tokens, this will cause depositors to be sent less tokens than needed (or none). This is especially unsafe because the tokens that were lacking are not resembled in accountings at all. Thus a depositor may invoke the safeConcurTransfer
and not receive tokens they were supposed to.
Manual analysis
Use usual safeTransfer
instead of safeConcurTransfer
.
#0 - r2moon
2022-02-15T15:33:44Z
duplicated with https://github.com/code-423n4/2022-02-concur-findings/issues/262
#1 - GalloDaSballo
2022-04-04T21:36:27Z
Duplicate of #262
🌟 Selected for report: hickuphh3
Also found by: 0x1f8b, 0xw4rd3n, BouSalman, CertoraInc, Czar102, Dravee, IllIllI, Randyyy, Rhynorater, Ruhum, ShadowyNoobDev, Sleepy, SolidityScan, WatchPug, bitbopper, cccz, cryptphi, csanuragjain, defsec, gzeon, harleythedog, hubble, hyh, kenta, kirk-baird, leastwood, mtz, pauliax, peritoflores, rfa, robee, samruna, throttle, wuwe1, ye0lde
127.2691 USDC - $127.27
https://github.com/code-423n4/2022-02-concur/blob/main/contracts/MasterChef.sol#L50
Block average time can change significantly, changing protocol parameters. If time dependence is desired, use block.timestamp
. This can vary by as much as 15s (default Geth implementation), while block times can change measured time not by a constant, but scale it. Note that block time change WILL happen because of difficulty bomb and Ethereum 2.0.
Manual analysis
Use block.timestamp
for calculations where time is crucial.
#0 - r2moon
2022-02-16T16:09:53Z
reward will be accumulated per block
#1 - GalloDaSballo
2022-04-04T21:41:38Z
I don't believe that in this case the severity of the finding is valid, at most a block will be delayed by a few seconds and over time difficulty is adjusted so that blocks are produced in a predictable way.
Given the circumstances I believe non-critical to be more appropriate as severity
#2 - JeeberC4
2022-04-21T01:53:29Z
Generating QA Report as warden had not submitting and judge downgraded issue. Preserving original title: Block average time
#3 - GalloDaSballo
2022-04-27T14:57:49Z
1+++