🛡️ CVE-2025-27104 — vyper

🟢 CVSS 2.0 — Low ⚠️ Exploit Public CWE-662 OSV
2.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Vyper has a double eval in For List Iter

Multiple evaluation of a single expression is possible in the iterator target of a for loop. While the iterator expression cannot produce multiple writes, it can consume side effects produced in the loop body (e.g. read a storage variable updated in the loop body) and thus lead to unexpected program behavior. Specifically, reads in iterators which contain an ifexp (e.g. for s: uint256 in ([read(), read()] if True else [])) may interleave reads with writes in the loop body.

The fix is tracked in https://github.com/vyperlang/vyper/pull/4488.

Vulnerability Details

Vyper for loops allow two kinds of iterator targets, namely the range() builtin and an iterable type, like SArray and DArray.

During codegen, iterable lists are required to not produce any side-effects (in the following code, range_scope forces iter_list to be parsed in a constant context, which is checked against is_constant).

```python

def _parse_For_list(self):

with self.context.range_scope():

iter_list = Expr(self.stmt.iter, self.context).ir_node

...

def range_scope(self):

prev_value = self.in_range_expr

self.in_range_expr = True

yield

self.in_range_expr = prev_value

def is_constant(self):

return self.constancy is Constancy.Constant or self.in_range_expr

```

However, this does not prevent the iterator from consuming side effects provided by the body of the loop. For dynamic arrays, the compiler simply panics:

```vyper

x: DynArray[uint256, 3]

@external

def test():

for i: uint256 in (self.usesideeffect() if True else self.usesideeffect()):

pass

@view

def usesideeffect() -> DynArray[uint256, 3]:

return self.x

```

For SArrays on the other hand, iter_list is instantiated in the body of a repeat ir, so it can be evaluated several times.

Here are three illustrating examples. In the first example, the following test case pre-evaluates the iter list and stores the result to a temporary list in memory. So the list is only evaluated once, before entry into the loop body, and the log output will be 0, 0, 0.

```vyper

event I:

i: uint256

x: uint256

@deploy

def __init__():

self.x = 0

@external

def test():

for i: uint256 in [self.usesideeffect(), self.usesideeffect(), self.usesideeffect()]:

self.x += 1

log I(i)

@view

def usesideeffect() -> uint256:

return self.x

```

However, in the next two examples, because the iterator target is not a list literal, it will be evaluated in the loop body. In the second example, iter_list is an ifexp, thus it will be evaluated lazily in the loop body. The log output will be 0, 1, 2 due to consumption of side effects.

```vyper

event I:

i: uint256

x: uint256

@deploy

def __init__():

self.x = 0

@external

def test():

for i: uint256 in ([self.usesideeffect(), self.usesideeffect(), self.usesideeffect()] if True else self.otherclause()):

self.x += 1

log I(i)

@view

def usesideeffect() -> uint256:

return self.x

@view

def otherclause() -> uint256[3]:

return [0, 0, 0]

```

In the third example, iter_list is also an ifexp, thus it will only be evaluated in the loop body. The log output will be 0, 1, 2 due to consumption of side effects.

```vyper

event I:

i: uint256

x: uint256[3]

@deploy

def __init__():

self.x = [0, 0, 0]

@external

def test():

for i: uint256 in (self.usesideeffect() if True else self.otherclause()):

self.x[0] += 1

self.x[1] += 1

self.x[2] += 1

log I(i)

@view

def usesideeffect() -> uint256[3]:

return self.x

@view

def otherclause() -> uint256[3]:

return [0, 0, 0]

```

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs low-level privileges on the target. No user interaction is required. Rated impact: confidentiality low, integrity low, availability none.

Affected software

CVE-2025-27104 is recorded against 1 package.

  • vyper (fixed in 0.4.1)

Timeline and source

Published on 21 February 2025 and last revised on 17 June 2026. A public exploit is known to exist, which raises the urgency of patching considerably. A vendor advisory or fix has been published. Record sourced from OSV.

References

github.com (Web)
nvd.nist.gov (Advisory)
github.com (Web)
github.com (Web)
github.com (Package)

Details

Severity LOW
CVSS Score 2.0
CVSS Vector CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N
CWE CWE-662
Public Exploit ⚠️ Yes
Source OSV
Published 2025-02-21
Updated 2026-08-12
Modified 2026-06-17

Affected Packages

Software From version Fixed in
vyper 0.4.1

Similar Threats

Exploit Protection

Are you running vyper?

CVE-2025-27104 carries CVSS 2.0 Low rating and a public exploit already exists. BotEraser checks your installation against this and other known CVE records, and blocks IPs associated with exploit activity.

Check My Site For CVE-2025-27104 →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.