This repository has been archived by the owner on Jun 11, 2023. It is now read-only.
roguereddwarf - HatsSignerGateBase: valid signer threshold can be bypassed because HSG checks signatures differently from Safe which allows exploitation #50
Labels
Fix Approved
Has Duplicates
A valid issue with 1+ other issues describing the same vulnerability
High
A valid High severity issue
HSG
Reward
A payout will be made for this issue
Sponsor Confirmed
The sponsor acknowledged this issue is valid
Will Fix
The sponsor confirmed this issue will be fixed
roguereddwarf
high
HatsSignerGateBase: valid signer threshold can be bypassed because HSG checks signatures differently from Safe which allows exploitation
Summary
This report deals with how the
HatsSignerGate
and theSafe
check signatures differently which opens the door to exploitation.I will show how this allows a valid signer that has become invalid but not yet removed from the
owners
of the Safe to continue signing transactions. The invalid signer can effectively sign transactions as though he was valid.Also there is the possibility of valid signers calling
Safe.addOwnerWithThreshold
. When an owner is added to the Safe but not a valid signer he can still sign transactions and the HSG will not recognize that there are not enough valid signatures.To summarize, the issue is caused by this:
threshold
signatures are valid. However the HSG logic checks that ANY of the signatures are signed by valid signers. The HSG logic does not check the same signatures as the Safe.Essentially the Safe and HSG logic are applying different checks to different signatures.
Vulnerability Detail
A transaction is executed by calling Safe.execTransaction
First the signatures are checked by the Safe Link then the
checkTransaction
function is executed on the guard (HatsSignerGate) LinkThe HatsSignerGate then executes
countValidSignatures
to check if enough signatures were signed by valid signers LinkWith all prerequisites out of the way, we can now get into the actual issue.
The Safe calls
checkNSignatures
to check if the firstthreshold
signatures in thesignatures
bytes are valid LinkSo if
threshold=5
but we provide say 7 signatures, the last two signatures are not checked.If the first 5 signatures are valid the check passes successfully.
The issue is that the HSG
countValidSignatures
function iterates over ALL signatures and tries to find enough valid signers such thatthreshold
is reached Link.So imagine the following scenario:
threshold=3
and 3 owners are valid signers.owners
.signatures
bytes. He also appends a signature of a valid signer from a previous transaction. So there are now 4 signatures in thesignatures
bytes.Safe.execTransaction
. The Safe checks the first 3 signatures to be valid signatures from owners. The check passes. The HSG checks that there are at least 3 signatures signed by valid signers. Which also passes.Important: Bob can pass a 4th signature from a previous transaction because two of the signature types used in HSG do not check that the correct data has been signed https://github.com/Hats-Protocol/hats-zodiac/blob/9455cc0957762f5dbbd8e62063d970199109b977/src/HatsSignerGateBase.sol#L561-L568.
To summarize: Bob was able to sign a transaction even though he was no longer a valid signer.
Further notes
Another thing to note is that HSG does not check signatures for uniqueness so if Bob would have to append multiple signatures from valid signers he could just add the same signature multiple times.
Also the HSG does not check that
ecrecover
does not return the zero address as owner which it does if the signature is invalid.These checks are implemented in the Safe. So by implementing the mitigation I suggest below the Safe and HSG will check the same signatures. So there is no need to have these checks in the HSG as well.
However due to this bug (checking different signatures), the signer hat might be transferred to
address(0)
which then causes invalid signatures to be considered valid.Impact
Owners of the Safe that are not valid signers can sign transactions.
Code Snippet
Also have a look at the
@audit-info
comments that further explain the issue.https://github.com/safe-global/safe-contracts/blob/cb22537c89ea4187f4ad141ab2e1abf15b27416b/contracts/Safe.sol#L135-L217
https://github.com/safe-global/safe-contracts/blob/cb22537c89ea4187f4ad141ab2e1abf15b27416b/contracts/Safe.sol#L270-L330
https://github.com/Hats-Protocol/hats-zodiac/blob/9455cc0957762f5dbbd8e62063d970199109b977/src/HatsSignerGateBase.sol#L445-L503
https://github.com/Hats-Protocol/hats-zodiac/blob/9455cc0957762f5dbbd8e62063d970199109b977/src/HatsSignerGateBase.sol#L547-L591
Tool used
Manual Review
Recommendation
I propose that in the HatsSignerGate only the first
threshold
signatures are checked. Such that both the Safe and HSG check the SAME signatures.Fix:
Instead of checking all signatures, only the first
threshold
ones will be checked.Also there is no need to check the length of the
signatures
bytes. All those checks are done by the Safe already.The text was updated successfully, but these errors were encountered: