Party DAO - rvierdiiev's results

Protocol for group coordination.

General Information

Platform: Code4rena

Start Date: 31/10/2023

Pot Size: $60,500 USDC

Total HM: 9

Participants: 65

Period: 10 days

Judge: gzeon

Total Solo HM: 2

Id: 301

League: ETH

PartyDAO

Findings Distribution

Researcher Performance

Rank: 19/65

Findings: 2

Award: $435.06

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Awards

199.934 USDC - $199.93

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
duplicate-233

External Links

Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernance.sol#L636-L638 https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernance.sol#L1098-L1100

Vulnerability details

Proof of Concept

When proposal is created, then number of hosts is stored for it. In case if proposal succeeded and all hosts have accepted it, then it's considered as unanimous and execution delay(which is another point of security) is skipped. Pls, note that _hostsAccepted requires that accepted hosts amount should be strictly equal to host count that was stored in proposal.

So in case, if host accepts proposal, then count of accepted hosts is incremented.

Also PartyGovernance has abdicateHost function which allows host to move his role to another account. https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernance.sol#L457-L472

    function abdicateHost(address newPartyHost) external {
        _assertHost();
        // 0 is a special case burn address.
        if (newPartyHost != address(0)) {
            // Cannot transfer host status to an existing host.
            if (isHost[newPartyHost]) {
                revert InvalidNewHostError();
            }
            isHost[newPartyHost] = true;
        } else {
            // Burned the host status
            --numHosts;
        }
        isHost[msg.sender] = false;
        emit HostStatusTransferred(msg.sender, newPartyHost);
    }

Using this function, host can accept proposal as many times as needed to make it unanimous. He just needs to accept proposal, then abdicateHost to another his address and so on. As result, host can ability to use this function in his interests to reach needed amount of hosts needed(and skip execution delay) or even to not allow _hostsAccepted function show true, when needed amount of hosts has accepted proposal(he can make accepted hosts count be bigger, than needed).

Impact

Malicious host can use _hostsAccepted feature in his own interests.

Tools Used

VsCode

I don't know good solution here. With current design this functionality will not work normally.

Assessed type

Error

#0 - c4-pre-sort

2023-11-12T11:11:20Z

ydspa marked the issue as duplicate of #538

#1 - c4-pre-sort

2023-11-12T14:14:53Z

ydspa marked the issue as sufficient quality report

#2 - c4-judge

2023-11-19T13:32:14Z

gzeon-c4 marked the issue as satisfactory

Findings Information

🌟 Selected for report: TresDelinquentes

Also found by: 0xadrii, 3docSec, klau5, leegh, mahdikarimi, minimalproxy, rvierdiiev

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
insufficient quality report
duplicate-418

Awards

235.1319 USDC - $235.13

External Links

Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/ETHCrowdfundBase.sol#L202-L204 https://github.com/code-423n4/2023-10-party/blob/main/contracts/party/PartyGovernanceNFT.sol#L195-L198

Vulnerability details

Proof of Concept

When someone is going to contribute to InitialETHCrowdfund, then _processContribution is called. Contribution can be called for yourself, or on behalf of someone.

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/ETHCrowdfundBase.sol#L201-L208

        address oldDelegate = delegationsByContributor[contributor];
        if (msg.sender == contributor || oldDelegate == address(0)) {
            // Update delegate.
            delegationsByContributor[contributor] = delegate;
        } else {
            // Prevent changing another's delegate if already delegated.
            delegate = oldDelegate;
        }

As you can see, in case if user already has delegate, then no one else can change it. But in case if it's not set yet, then caller can set delegator for user. This check is done only in the ETHCrowdfundBase._processContribution function and delegator inside InitialETHCrowdfund._contribute is not changed.

After that, InitialETHCrowdfund._contribute continue it's work and it provides originally passed delegator, that was provided by called to the Party.mint function.

So when PartyGovernanceNFT.mint is executed it actually fetches user's current delegate and rewrites provided one, in case if current delegate is not 0.

So later, voting power is added to the current delegator of token owner.

So what we have here is that attacker can frontrun user's first contribution(when he doesn't have any delegate yet) with minimum contribution and delegator that he would like to have. So then, when user's contribution will be executed, then his delegator will be ignored and the one, provided by attacker before will be used. As result, attacker was able to increase his voting power.

Impact

Attacker can steal user's voting power.

Tools Used

VsCode

In this case we can't understand if user has agreed to use provided delegate. Maybe better to use offchain signatures for such cases. In case if someone wants to contribute on behalf of someone, then he should provide user's signature.

Or allow third party to delegate only for current delegator of owner. In case if it's first nft of user, then delegator should be user itself.

Assessed type

Error

#0 - c4-pre-sort

2023-11-12T04:59:23Z

ydspa marked the issue as duplicate of #334

#1 - c4-pre-sort

2023-11-12T04:59:26Z

ydspa marked the issue as insufficient quality report

#2 - c4-pre-sort

2023-11-13T11:38:50Z

ydspa marked the issue as remove high or low quality report

#3 - c4-pre-sort

2023-11-13T11:39:23Z

ydspa marked the issue as insufficient quality report

#4 - c4-judge

2023-11-19T17:28:19Z

gzeon-c4 marked the issue as duplicate of #418

#5 - c4-judge

2023-11-19T17:30:02Z

gzeon-c4 marked the issue as satisfactory

#6 - c4-judge

2023-11-19T17:30:49Z

gzeon-c4 marked the issue as partial-25

#7 - c4-judge

2023-11-20T18:46:41Z

gzeon-c4 changed the severity to 2 (Med Risk)

#8 - rvierdiyev

2023-11-21T21:20:28Z

hello @gzeon-c4 can i ask why this report receives 25%? looks like it describes same as #418

#9 - gzeon-c4

2023-11-23T08:09:25Z

The writeup is ambiguous, "attacker can frontrun user's first contribution" ONLY if it is contributed on behalf by someone else. The user can always rewrite the delegation due to the msg.sender == contributor check.

#10 - rvierdiyev

2023-11-23T08:27:21Z

@gzeon-c4 i know that it can be done only if is contributed on behalf, i have explained that in the report(i mean that attacker will be the one who will do that first contribution on behalf of user)

As you can see, in case if user already has delegate, then no one else can change it. But in case if it's not set yet, then caller can set delegator for user.

also user can't change real delegation after it is set as i explained here, current one will be used

So when PartyGovernanceNFT.mint is executed it actually fetches user's current delegate and rewrites provided one, in case if current delegate is not 0.

So later, voting power is added to the current delegator of token owner.

And in order to redelagate correctly user should call delegateVotingPower.

I should say, that this reporst is exactly the same as #418 and i have explained all parts that cause the problem

  1. Anyone can contribute on behalf of someone to set delegate for it in case if no delegate was set before
  2. When user contributes again later, then old delegate is used(so new provided one is ignored)
  3. Voting power after contribution is added to the current delegator(which will be attacker is this case).

Can you pls, check this report again, as i believe that it should get full credit.

thank you

#11 - gzeon-c4

2023-11-23T08:57:28Z

Fair, admittedly the report is a bit hard to understand at first sight.

#12 - c4-judge

2023-11-23T08:57:35Z

gzeon-c4 marked the issue as satisfactory

#13 - rvierdiyev

2023-11-23T09:34:54Z

Fair, admittedly the report is a bit hard to understand at first sight.

i am sorry for that i guess it's because of language barrier

Findings Information

🌟 Selected for report: TresDelinquentes

Also found by: 0xadrii, 3docSec, klau5, leegh, mahdikarimi, minimalproxy, rvierdiiev

Labels

bug
2 (Med Risk)
partial-25
insufficient quality report
duplicate-418

Awards

235.1319 USDC - $235.13

External Links

Lines of code

https://github.com/code-423n4/2023-10-party/blob/main/contracts/crowdfund/InitialETHCrowdfund.sol#L297-L298

Vulnerability details

Proof of Concept

Using InitialETHCrowdfund._contribute, user can provide some funds together with delegate and receive some voting power instead and delegate it(together with all other user's voting power) to provided delegate.

It's possible that user will provide 0 amount. As comment states it can be used to change user's delegator. The problem is that this will change delegator only inside ETHCrowdfundBase, which is actually useless for the Party and then function will return. And real delegator in the Party will not be changed in this case.

As result, user will think that he had changed delegator, but in reality it will be same.

Impact

Delegator for user will not be changed.

Tools Used

VsCode

In case if amount is 0, then change delegator for user.

if (amount == 0) { delegateVotingPower(delegate); return; }

But be careful with using this by third parties. This should not be allowed or somehow restricted.

Assessed type

Error

#1 - c4-pre-sort

2023-11-12T13:50:29Z

ydspa marked the issue as insufficient quality report

#2 - c4-judge

2023-11-19T18:06:18Z

gzeon-c4 marked the issue as unsatisfactory: Invalid

#3 - rvierdiyev

2023-11-22T06:39:27Z

hello @gzeon-c4 would you consider this report as as duplicate of #311, however partially? i acknowledge that i have missed whole problem and impact, however i find part of it

from primary issue

If voting power is 0, _contribute returns and new delegate is NOT propagated to party contract (InitialETHCrowdfund.sol#L298).

this is exactly what describes this report.

i would be happy to get partial 50 or even less if you think so. thank you

#4 - c4-judge

2023-11-23T08:11:05Z

gzeon-c4 marked the issue as duplicate of #311

#5 - c4-judge

2023-11-23T08:11:10Z

gzeon-c4 marked the issue as partial-25

#6 - c4-judge

2023-11-23T08:52:36Z

gzeon-c4 marked the issue as duplicate of #418

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter