Every CVE Search/ Get API key

CVE-2023-30629

Vyper's raw_call with outsize=0 and revert_on_failure=False returns incorrect success value

7.5 HighFix available

Vyper is a Pythonic Smart Contract Language for the ethereum virtual machine. In versions 0.3.1 through 0.3.7, the Vyper compiler generates the wrong bytecode. Any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False. A patch is available and, as of time of publication, anticipated to be part of Vyper 0.3.8. As a workaround, one may always put max_outsize>0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
High
Availability
None

Exploit likelihood

0.88%Up 0.8 points since Apr 25, 2023
90%50%10%1%

What each source reports

CVE List Score used 7.5

Vyper's raw_call with outsize=0 and revert_on_failure=False returns incorrect success value

Vyper is a Pythonic Smart Contract Language for the ethereum virtual machine. In versions 0.3.1 through 0.3.7, the Vyper compiler generates the wrong bytecode. Any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False. A patch is available and, as of time of publication, anticipated to be part of Vyper 0.3.8. As a workaround, one may always put max_outsize>0.

Record
CVE-2023-30629
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Weakness
CWE-670
Updated
2026-11-02
EUVDEUVD-2023-0263 7.5

Vyper is a Pythonic Smart Contract Language for the ethereum virtual machine. In versions 0.3.1 through 0.3.7, the Vyper compiler generates the wrong bytecode. Any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False. A patch is available and, as of time of publication, anticipated to be part of Vyper 0.3.8. As a workaround, one may always put max_outsize>0.

Record
EUVD-2023-0263
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Updated
2026-11-03
GitHub AdvisoriesGHSA-w9g2-3w7p-72g9 8.7

Incorrect success value returned in vyper

Background

During the audit of Lido's Gate Seals code statemind team identified a weird behavior of the code that uses raw_call: https://github.com/lidofinance/gate-seals/blob/051593e74df01a4131c485b4fda52e691cd4b7d8/contracts/GateSeal.vy#L164 .

Construction like this:

success = raw_call(
    sealable,
    _abi_encode(SEAL_DURATION_SECONDS, method_id=method_id("pauseFor(uint256)")),
    revert_on_failure=False
)

was not fully documented: https://docs.vyperlang.org/en/v0.3.7/built-in-functions.html#raw_call .

The documentation says that: if max_outsize=0 it should return nothing and then it says that if revert_on_failure=False it should return a success flag in the tuple of response, but what if max_outsize=0 and revert_on_failure=False.

<img width="715" alt="image" src="https://user-images.githubusercontent.com/22330612/232125364-d2b3bbac-0b4f-40cb-80ff-f55d8eafef44.png">

So the team started researching what exactly happened in that case, after some research we found that the Vyper compiler generates the wrong bytecode in that case, it generates the sequence:

CALL // call
MLOAD // MLOAD is wrong since the CALL result is already stored in the stack

Impact

Example of buggy code:

@external
def returnSome(calling: address, a: uint256) -> bool:
    success: bool = false
    success = raw_call(
        calling,
        _abi_encode(a, method_id=method_id("a(uint256)")),
        revert_on_failure=False
        )

any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False.

Patches

Fix by @charles-cooper https://github.com/vyperlang/vyper/commit/851f7a1b3aa2a36fd041e3d0ed38f9355a58c8ae

Workarounds

The simple workaround is always to put max_outsize>0. Workaround example https://github.com/lidofinance/gate-seals/pull/5/files

References

Lido's fix: https://github.com/lidofinance/gate-seals/pull/5/files

Record
GHSA-w9g2-3w7p-72g9
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Weakness
CWE-670
Updated
2026-11-02
NVD 7.5

Vyper is a Pythonic Smart Contract Language for the ethereum virtual machine. In versions 0.3.1 through 0.3.7, the Vyper compiler generates the wrong bytecode. Any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False. A patch is available and, as of time of publication, anticipated to be part of Vyper 0.3.8. As a workaround, one may always put max_outsize>0.

Record
CVE-2023-30629
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Weakness
CWE-670
Updated
2026-11-02
OSV 7.5

Vyper's raw_call with outsize=0 and revert_on_failure=False returns incorrect success value

Vyper is a Pythonic Smart Contract Language for the ethereum virtual machine. In versions 0.3.1 through 0.3.7, the Vyper compiler generates the wrong bytecode. Any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False. A patch is available and, as of time of publication, anticipated to be part of Vyper 0.3.8. As a workaround, one may always put max_outsize>0.

Record
CVE-2023-30629
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Weakness
CWE-670
Updated
2026-11-02
OSVGHSA-w9g2-3w7p-72g9 8.7

Incorrect success value returned in vyper

Background

During the audit of Lido's Gate Seals code statemind team identified a weird behavior of the code that uses raw_call: https://github.com/lidofinance/gate-seals/blob/051593e74df01a4131c485b4fda52e691cd4b7d8/contracts/GateSeal.vy#L164 .

Construction like this:

success = raw_call(
    sealable,
    _abi_encode(SEAL_DURATION_SECONDS, method_id=method_id("pauseFor(uint256)")),
    revert_on_failure=False
)

was not fully documented: https://docs.vyperlang.org/en/v0.3.7/built-in-functions.html#raw_call .

The documentation says that: if max_outsize=0 it should return nothing and then it says that if revert_on_failure=False it should return a success flag in the tuple of response, but what if max_outsize=0 and revert_on_failure=False.

<img width="715" alt="image" src="https://user-images.githubusercontent.com/22330612/232125364-d2b3bbac-0b4f-40cb-80ff-f55d8eafef44.png">

So the team started researching what exactly happened in that case, after some research we found that the Vyper compiler generates the wrong bytecode in that case, it generates the sequence:

CALL // call
MLOAD // MLOAD is wrong since the CALL result is already stored in the stack

Impact

Example of buggy code:

@external
def returnSome(calling: address, a: uint256) -> bool:
    success: bool = false
    success = raw_call(
        calling,
        _abi_encode(a, method_id=method_id("a(uint256)")),
        revert_on_failure=False
        )

any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False.

Patches

Fix by @charles-cooper https://github.com/vyperlang/vyper/commit/851f7a1b3aa2a36fd041e3d0ed38f9355a58c8ae

Workarounds

The simple workaround is always to put max_outsize>0. Workaround example https://github.com/lidofinance/gate-seals/pull/5/files

References

Lido's fix: https://github.com/lidofinance/gate-seals/pull/5/files

Record
GHSA-w9g2-3w7p-72g9
CVSS 4.0
8.7 HighCVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Weakness
CWE-670
Updated
2026-11-02
OSVPYSEC-2023-131 7.5

Vyper is a Pythonic Smart Contract Language for the ethereum virtual machine. In versions 0.3.1 through 0.3.7, the Vyper compiler generates the wrong bytecode. Any contract that uses the raw_call with revert_on_failure=False and max_outsize=0 receives the wrong response from raw_call. Depending on the memory garbage, the result can be either True or False. A patch is available and, as of time of publication, anticipated to be part of Vyper 0.3.8. As a workaround, one may always put max_outsize>0.

Record
PYSEC-2023-131
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
vyper
PyPI
0.3.1 up to 0.3.8
0.3.8
vyper
PyPI
0.3.1 up to 0.3.8, plus listed versions
0.3.20.3.30.3.40.3.50.3.60.3.7
0.3.8

History

History
RecordedChangedSources
aliases, publishedEUVD
first indexedCVE List, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2023-30629 is a high vulnerability (CVSS 7.5) in Vyperlang Vyper, published April 24, 2023. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.88%, the 59th percentile. Fixed in vyper 0.3.8.

References

Show 4 moreShow less
MoveEnter Open