The Sablier Flow smart contracts lack an upgradeability mechanism, making the protocol's logic immutable post-deployment. This absence restricts the ability to address critical bugs, implement enhancements, or adapt to evolving security standards without deploying entirely new contracts. Consequently, any discovered vulnerabilities remain unfixable within the existing contract framework, potentially compromising user funds and the protocol's integrity.
Explanation:
We attempted to deploy a proxy contract that delegates calls to the SablierFlow
implementation using delegatecall
. However, the SablierFlow
contract inherits from NoDelegateCall
, which includes a modifier that reverts any delegate calls. This ensures that the contract cannot be used as an implementation behind a proxy, effectively preventing any upgrade attempts via this method.
Explanation:
The SablierFlow
contract does not implement any upgrade functions such as upgradeTo
or upgradeToAndCall
. Any attempt to invoke such functions will fail, as they are neither defined nor inherited from any parent contracts. This confirms the absence of inherent upgrade mechanisms within the contract.
Explanation:
We attempted to perform a delegatecall
to the adjustRatePerSecond
function of the SablierFlow
contract. Due to the NoDelegateCall
modifier, this call will revert, preventing any unauthorized state modifications through delegate calls. This mechanism ensures that the contract's logic remains immutable and secure against such attack vectors.
Explanation:
This snippet inspects the contract's bytecode for the presence of the DELEGATECALL
opcode (0xF4
). The absence of this opcode confirms that the contract does not support delegate calls, further reinforcing the lack of an upgradeability mechanism. Such bytecode analysis ensures that the contract cannot be exploited through hidden proxy patterns or delegate call-based upgrades.
The absence of an upgradeability mechanism in the Sablier Flow contracts presents the following risks:
Immutability of Logic: Once deployed, the contract's logic cannot be altered. This rigidity means that any discovered bugs or required enhancements cannot be addressed without deploying a new contract and migrating users, which is operationally challenging and may lead to user dissatisfaction.
Security Risks: Critical vulnerabilities remain unpatchable within the existing contract. Attackers could exploit these vulnerabilities indefinitely until a new contract is deployed, potentially leading to significant financial losses for users.
Operational Challenges: Upgrading requires complex migration processes, including transferring state and user funds to a new contract. This process can be error-prone and may disrupt the user experience, eroding trust in the protocol.
Competitive Disadvantage: Inability to iterate and improve quickly can place the protocol at a disadvantage compared to competitors that can seamlessly upgrade their contracts to introduce new features or enhance security.
Manual Review
To address the absence of an upgradeability mechanism in the Sablier Flow contracts, the following measures are recommended:
Choose a Suitable Proxy Pattern:
Universal Upgradeable Proxy Standard (UUPS): Offers a gas-efficient and flexible approach where the implementation contract contains the upgrade logic itself.
Transparent Proxy: Separates admin functions from user functions, preventing accidental upgrades.
Steps to Implement UUPS Proxy:
Create a Proxy Contract:
Separate Logic and Storage:
Ensure that storage variables reside in the proxy, while logic is contained in the implementation contract.
Initialize Properly:
Replace constructors with initializer functions to set initial states.
Restrict Upgrade Permissions:
Ensure only authorized roles (e.g., Admin) can perform upgrades to prevent unauthorized modifications.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.