Comment on page
Past paid bounties
This list includes valid submissions from past and current contract versions for which a bounty has been paid.
We use a MultiSend library to batch multiple transactions together. A transaction could be created that would self-destruct the contract. While this would not have put any funds at risk, user experience would have been seriously impacted.
Since the beginning of the bug bounty period, the contract update has been live on the Ethereum Mainnet. We performed extensive internal testing and discovered an edge case where a Safe could not receive funds from another contract via
transfer. This was due to additional gas costs caused by the emission of additional events and gas price changes in the latest hard fork. This issue has been fixed, and more details can be found on GitHub.
A bug in the
OwnerManager.solallows duplicate owners to be set when the duplicated address is next to itself in the
_ownersarray. This could cause unexpected behavior. While stealing funds from existing Safes is impossible, it is unexpected, and user funds might be locked. During Safe creation, the threshold of a Safe could be set to something unreachable, making it impossible to execute a transaction afterward.
The contracts allow to set a Safe as an owner of itself. This has the same effect as lowering the threshold by 1, as it is possible for anyone to generate a valid signature for the Safe itself when triggering
execTransaction. This is especially an issue for Safes with a threshold of 1. Anyone can execute transactions if a Safe with threshold 1 adds itself as an owner.
To our knowledge, there is no actual use case where it would make sense to set a Safe as an owner of itself. Hence, only a few number of Safes used themselves as owners. Most of these Safes could be contacted, and the Safe has been removed as an owner. The Safes still affected are Safes used for testing by us or Safes owned by a single owner with a threshold > 1 (so no immediate risk).
To fix this, the next contract update will prevent the Safe as its owner via
require(owner != address(this), "Safe can't be an owner"). This check can be performed when adding owners and/or when checking signatures.
The method getModuledPaginated is used to return enabled modules page by page. For this, a
pageSizeneed to be specified, and the method will return an array of Safe Module addresses and
next. This next can be used as the
startto load the next page. When another page exists, then
nextis a module address. This module address, however, will not be present in any of the returned arrays. While this does not put any user assets at risk directly, it could lead to a wrong perception of the enabled modules of a Safe and, thereby, its state.
The workaround is to append the
nextto the returned array of module addresses if it is not the zero or sentinel address. Alternatively, the last element of the returned array can be used as the
startfor the next page.