-
Notifications
You must be signed in to change notification settings - Fork 968
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tool: add detector for multiple new reinitializers #2536
tool: add detector for multiple new reinitializers #2536
Conversation
|
||
# region wiki_recommendation | ||
WIKI_RECOMMENDATION = """ | ||
Do not use multiple reinitializers with higher versions in the updated contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we add what should be done instead? I think they should be combined into a single re-initializer per upgrade based off the description of the issue, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I added a suggestion, thanks.
results = [] | ||
if len(new_reinitializer_funcs) > 1: | ||
for f in new_reinitializer_funcs: | ||
info = [f, " multiple new reinitializers.\n"] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
info = [f, " multiple new reinitializers.\n"] | |
info = [f, " multiple new reinitializers which should be combined into one per upgrade.\n"] |
Same general idea as https://github.com/crytic/slither/pull/2536/files#r1722628467
Can you run |
I am trying to fix the CI failure in #2537 |
Thanks @QiuhaoLi, these are great additions! |
@0xalpharush Thanks for the review :) |
When upgrading a proxy's implementation with reinitializer, developers could errorly write multiple new reinitializers. If the new reinitializer with a higher version is called first, the reinitializer with a lower version can't be called later (you can't call a reinitializer with a lower version) and may leave uninitalized state variables.
This could lead to severe results in the real world. For example, the Ronin Network prepared two upgrades for their gateway contract and wrote two reinitializers (
initializeV3()
andinitializeV4()
). However, the developer calls theinitializeV4()
first and leaves the state variables_operatorWeight
and_totalOperatorWeight
uninitialized, which should be set in theinitializeV3()
. So attackers can bypass the vote weight and withdraw assets directly [1] [2] [3].The best practice for this issue is never to introduce more than one reinitializer in one updated implementation. This PR will add a detector to the
slither-check-upgradeability
to check if multiple new reinitializes are introduced and report a low-severity warning. For example: