You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Threshold of existing Safe, could cause transaction failures
Summary
When creating a new HSG module it is possible to attach it to an existing Safe. The existing Safe can have an already set up owners and threshold. However, even though the owners receive the required by the HSG module hats, the transactions will not succeed.
Root Cause
The root cause of this issue is due to the unchecked number of Safe's owners in the initializer of the HSG module. Every other change whether of the owners(ref), or the ThresholdConfig(ref), the number of owners are checked against the boundaries described in the the ThresholdConfig and the Safe's threshold is updated according to that value. In checkTransaction(), the Safe's threshold is expected to be equal to the result of _getRequiredValidSignatures.
However when a new HSG module is attached to an existing Safe, or the Safe is migrated to a new HSG, the Safe's threshold is not updated to match the boundaries in the ThresholdConfig. Which will lead to failures in checkTransaction(), because the Safe's threshold is expected to be equal to the result of the _getRequiredValidSignatures.
Internal pre-conditions
A HSG's ThresholdConfig should be ABSOLUTE, and target less than the number of owners of the Safe.
External pre-conditions
A Safe is created with threshold equal to the number of owners.
All owners receive valid signer's hats.
Attack Path
A HSG module is created and added to a Safe.
All owners of the Safe call claimSigner()
A transaction is executed using the Safe's executeTransaction(), which contains Safe's threshold number of valid signatures.
The checkTransaction() will fail.
Impact
When attaching a HSG module to an existing Safe, all transactions will revert due to the difference of the Safe's threshold and the module's target.
PoC
Let's assume that a Safe is created with 10 owners and a threshold of 5.
A HSG module is attached to it with a ThresholdConfig, with min=2 and target=7.
The Safe's threshold is in the boundaries of the HSG.
When a transaction is executed from the Safe, the checkTransaction is called.
This function fetches the Safe's threshold and owners.
After that it calculates the threshold which is required by the HSG module, using the number of owners.
In the given example it will require 7, because the number of owners is bigger than the module's target.
However the Safe's threshold i equal to 5, so the following check will fail:
if (threshold !=_getRequiredValidSignatures(owners.length)) revertThresholdTooLow();
Leading to the failure of the whole transaction.
Mitigation
Add checks and threshold updates like this:
// update the safe's threshold to match the new configaddress[] memory owners = safe.getOwners();
// get the required amount of valid signatures according to the new threshold config// and the current number of ownersuint256 newThreshold =_getRequiredValidSignatures(owners.length);
// the safe's threshold cannot be higher than the number of owners (safe's invariant)if (newThreshold > owners.length) {
newThreshold = owners.length;
}
safe.execChangeThreshold(newThreshold);
when a HSG module is attached to a Safe.
The text was updated successfully, but these errors were encountered:
Merry Marigold Ferret
Medium
Threshold of existing Safe, could cause transaction failures
Summary
When creating a new HSG module it is possible to attach it to an existing Safe. The existing Safe can have an already set up owners and threshold. However, even though the owners receive the required by the HSG module hats, the transactions will not succeed.
Root Cause
The root cause of this issue is due to the unchecked number of Safe's owners in the initializer of the HSG module. Every other change whether of the owners(ref), or the
ThresholdConfig
(ref), the number of owners are checked against the boundaries described in the theThresholdConfig
and the Safe's threshold is updated according to that value. In checkTransaction(), the Safe's threshold is expected to be equal to the result of _getRequiredValidSignatures.However when a new HSG module is attached to an existing Safe, or the Safe is migrated to a new HSG, the Safe's threshold is not updated to match the boundaries in the
ThresholdConfig
. Which will lead to failures in checkTransaction(), because the Safe's threshold is expected to be equal to the result of the _getRequiredValidSignatures.Internal pre-conditions
ThresholdConfig
should be ABSOLUTE, and target less than the number of owners of the Safe.External pre-conditions
Attack Path
claimSigner()
executeTransaction()
, which contains Safe's threshold number of valid signatures.checkTransaction()
will fail.Impact
When attaching a HSG module to an existing Safe, all transactions will revert due to the difference of the Safe's threshold and the module's target.
PoC
Let's assume that a Safe is created with 10 owners and a threshold of 5.
A HSG module is attached to it with a
ThresholdConfig
, with min=2 and target=7.The Safe's threshold is in the boundaries of the HSG.
When a transaction is executed from the Safe, the
checkTransaction
is called.This function fetches the Safe's threshold and owners.
After that it calculates the threshold which is required by the HSG module, using the number of owners.
In the given example it will require 7, because the number of owners is bigger than the module's target.
However the Safe's threshold i equal to 5, so the following check will fail:
Ref
Leading to the failure of the whole transaction.
Mitigation
Add checks and threshold updates like this:
when a HSG module is attached to a Safe.
The text was updated successfully, but these errors were encountered: