Vyper: Return inside for loop more than 1 level deepGHSA-vg88-3v92-rjx2
Fix: vyperlang/vyper#2110GHSA-vg88-3v92-rjx2 is a security vulnerability in vyper. A fix is available for vyper — see the affected versions and patch details below.
Real-World Exposure
vyperReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
VVE-2020-0002
Earlier today, we received a responsible disclosure of a potential issue from @michwill (developer of @curvefi) for Vyper users who use return statements inside for loops of nested internal calls. Returning inside a for loop causes an invalid jump dest, reverting the transaction unnecessarily.
MWE:
@internal
def _baz():
for i in range(1):
return # Stack underflow happens here
@internal
def _bar():
self._baz()
@external
def foo():
self._bar()
Impact
Impact is minor, it is unlikely a user would encounter this problem unless they were working with nested calls, and return statements inside calls. Even in that scenario, you would encounter a revert which should be noticeable with adequate testing. In limited circumstances, this could cause a DoS attack for public contracts under certain conditions.
Patches
Fixed in https://github.com/vyperlang/vyper/pull/2110. Please upgrade to Vyper 0.2.3
Workarounds
Not returning inside a for loop nested 2+ internal calls deep works as is:
@internal
def _baz():
for i in range(1):
pass
return # This works fine
@internal
def _bar():
self._baz()
@external
def foo():
self._bar()
For more information
If you have any questions or comments about this advisory:
- Chat with us in our gitter
- Open an issue in https://github.com/vyperlang/vyper
- Email us at [email protected]
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | vyper | ≥ 0.1.0b10&&< 0.2.3 | 0.2.3pip install --upgrade 'vyper==0.2.3' |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for vyper, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update vyper to 0.2.3 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-vg88-3v92-rjx2 is resolved across your whole dependency graph.
Workarounds
Cap what an attacker can consume: apply request size, rate and timeout limits in front of the affected component, and run it with memory and CPU limits so exhaustion degrades one worker rather than the whole service.
Frequently Asked Questions
Is GHSA-vg88-3v92-rjx2 in your dependencies?
Find it across PyPI, including transitive dependencies.