Every CVE Search/ Get API key

CVE-2025-21607

Success of Certain Precompile Calls not Checked in Vyper

2.3 LowFix available

Vyper is a Pythonic Smart Contract Language for the EVM. When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect. Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts. None the less an advisory has been made out of an abundance of caution. This issue is fixed in 0.4.1.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
High
Privileges needed
Low
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
Low
Availability
None

Exploit likelihood

0.67%Up 0.6 points since Jan 15, 2025
90%50%10%1%

What each source reports

CVE List Score used 2.3

Success of Certain Precompile Calls not Checked in Vyper

Vyper is a Pythonic Smart Contract Language for the EVM. When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect. Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts. None the less an advisory has been made out of an abundance of caution. This issue is fixed in 0.4.1.

Record
CVE-2025-21607
CVSS 4.0
2.3 LowCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-670
Updated
2026-11-02
EUVDEUVD-2025-0067 2.3

Vyper is a Pythonic Smart Contract Language for the EVM. When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect. Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts. None the less an advisory has been made out of an abundance of caution. This issue is fixed in 0.4.1.

Record
EUVD-2025-0067
CVSS 4.0
2.3 LowCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-vgf2-gvx8-xwc3 2.3

Vyper Does Not Check the Success of Certain Precompile Calls

Summary

When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect.

Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts.

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

Details

The relevant precompiles

EcRecover

EcRecover is used in vyper's ecrecover built-in. As the precompile consumes 3000 gas, any execution after an out-of-gas EcRecover call has at most 47 gas left.

Identity
  • The Identity precompile is used in vyper to perform memory copy operations. As its cost is variable, a variable amount of gas might be left after a failed call. The bigger the copy operation, the more gas can be left. Hence, a failed call to Identity could theoretically be followed by successful storage changes or emitted events.
  • Identity is no longer used when evm-version cancun is used (because MCOPY is used instead). In 0.4.0 cancun is default, in 0.3.10 cancun is an option, otherwise cancun is not available. As only pre-cancun versions are relevant, we don't have to consider transient storage operations succeeding a failed call to Identity.

The other precompiles

  • Calls to Sha2, ecAdd, and ecMul have success checks and have had them for a long time.
  • The precompiles modexp, ripe, blake, ecPairing, and Point Evaluation have no builtins in vyper.

PoC

In the following we provide concrete examples of incorrectly generated bytecode. These examples are not optimized, but rather Proof-of-Concepts. The list is also not exhaustive.

ecrecover use

  • Affected versions: 0.2.0 - 0.4.0
  • For older compiler versions (<=0.3.9) it behaves similarly to this older advisory. As no data is returned, the previous value of the memory word is returned to the user. Hence, any dirty bytes might be returned. Contracts with older compiler versions and ecrecover were checked.
  • For new vyper versions, the output buffer is zeroed, so when the call fails zero is returned. This is an incorrect result, but developers should anyway check for 0 as a failure case. Hence, this is unlikely to result in issues. However, we did search for such cases.
  • As mentioned above at most 47 gas is left after the failed call, hence a return is the most realistic scenario to be attacked.

Vulnerable Code:

@external
@view
def foo(hash: bytes32, v: uint256, r:uint256, s:uint256) -> address:
    return ecrecover(hash, v, r, s)

Problematic Call:

print(
    c.foo(
        binascii.unhexlify(
            "6c9c5e133b8aafb2ea74f524a5263495e7ae5701c7248805f7b511d973dc7055"
        ),
        28,
        78616903610408968922803823221221116251138855211764625814919875002740131251724,
        37668412420813231458864536126575229553064045345107737433087067088194345044408,
    )
)  # Returns 0x9eE53ad38Bb67d745223a4257D7d48cE973FeB7A

print(
    c.foo(
        binascii.unhexlify(
            "6c9c5e133b8aafb2ea74f524a5263495e7ae5701c7248805f7b511d973dc7055"
        ),
        28,
        78616903610408968922803823221221116251138855211764625814919875002740131251724,
        37668412420813231458864536126575229553064045345107737433087067088194345044408,
        gas=3000,
    )
)  # Returns 0x0000000000000000000000000000000000000000

Identity to copy Dynamic Arrays

  • Affected versions: 0.3.2 - 0.3.9
  • Dynamic Arrays might be copied on different occasions
  • That copy operation can fail leading to incorrect accesses afterwards …
Record
GHSA-vgf2-gvx8-xwc3
CVSS 4.0
2.3 LowCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-670, CWE-703
Updated
2026-11-02
NVD 2.3

Vyper is a Pythonic Smart Contract Language for the EVM. When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect. Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts. None the less an advisory has been made out of an abundance of caution. This issue is fixed in 0.4.1.

Record
CVE-2025-21607
CVSS 4.0
2.3 LowCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
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 2.3

Success of Certain Precompile Calls not Checked in Vyper

Vyper is a Pythonic Smart Contract Language for the EVM. When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect. Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts. None the less an advisory has been made out of an abundance of caution. This issue is fixed in 0.4.1.

Record
CVE-2025-21607
CVSS 4.0
2.3 LowCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-670
Updated
2026-11-02
OSVGHSA-vgf2-gvx8-xwc3 2.3

Vyper Does Not Check the Success of Certain Precompile Calls

Summary

When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect.

Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts.

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

Details

The relevant precompiles

EcRecover

EcRecover is used in vyper's ecrecover built-in. As the precompile consumes 3000 gas, any execution after an out-of-gas EcRecover call has at most 47 gas left.

Identity
  • The Identity precompile is used in vyper to perform memory copy operations. As its cost is variable, a variable amount of gas might be left after a failed call. The bigger the copy operation, the more gas can be left. Hence, a failed call to Identity could theoretically be followed by successful storage changes or emitted events.
  • Identity is no longer used when evm-version cancun is used (because MCOPY is used instead). In 0.4.0 cancun is default, in 0.3.10 cancun is an option, otherwise cancun is not available. As only pre-cancun versions are relevant, we don't have to consider transient storage operations succeeding a failed call to Identity.

The other precompiles

  • Calls to Sha2, ecAdd, and ecMul have success checks and have had them for a long time.
  • The precompiles modexp, ripe, blake, ecPairing, and Point Evaluation have no builtins in vyper.

PoC

In the following we provide concrete examples of incorrectly generated bytecode. These examples are not optimized, but rather Proof-of-Concepts. The list is also not exhaustive.

ecrecover use

  • Affected versions: 0.2.0 - 0.4.0
  • For older compiler versions (<=0.3.9) it behaves similarly to this older advisory. As no data is returned, the previous value of the memory word is returned to the user. Hence, any dirty bytes might be returned. Contracts with older compiler versions and ecrecover were checked.
  • For new vyper versions, the output buffer is zeroed, so when the call fails zero is returned. This is an incorrect result, but developers should anyway check for 0 as a failure case. Hence, this is unlikely to result in issues. However, we did search for such cases.
  • As mentioned above at most 47 gas is left after the failed call, hence a return is the most realistic scenario to be attacked.

Vulnerable Code:

@external
@view
def foo(hash: bytes32, v: uint256, r:uint256, s:uint256) -> address:
    return ecrecover(hash, v, r, s)

Problematic Call:

print(
    c.foo(
        binascii.unhexlify(
            "6c9c5e133b8aafb2ea74f524a5263495e7ae5701c7248805f7b511d973dc7055"
        ),
        28,
        78616903610408968922803823221221116251138855211764625814919875002740131251724,
        37668412420813231458864536126575229553064045345107737433087067088194345044408,
    )
)  # Returns 0x9eE53ad38Bb67d745223a4257D7d48cE973FeB7A

print(
    c.foo(
        binascii.unhexlify(
            "6c9c5e133b8aafb2ea74f524a5263495e7ae5701c7248805f7b511d973dc7055"
        ),
        28,
        78616903610408968922803823221221116251138855211764625814919875002740131251724,
        37668412420813231458864536126575229553064045345107737433087067088194345044408,
        gas=3000,
    )
)  # Returns 0x0000000000000000000000000000000000000000

Identity to copy Dynamic Arrays

  • Affected versions: 0.3.2 - 0.3.9
  • Dynamic Arrays might be copied on different occasions
  • That copy operation can fail leading to incorrect accesses afterwards …
Record
GHSA-vgf2-gvx8-xwc3
CVSS 4.0
2.3 LowCVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N
Weakness
CWE-670, CWE-703
Updated
2026-11-02
OSVPYSEC-2025-33 7.5

Vyper is a Pythonic Smart Contract Language for the EVM. When the Vyper Compiler uses the precompiles EcRecover (0x1) and Identity (0x4), the success flag of the call is not checked. As a consequence an attacker can provide a specific amount of gas to make these calls fail but let the overall execution continue. Then the execution result can be incorrect. Based on EVM's rules, after the failed precompile the remaining code has only 1/64 of the pre-call-gas left (as 63/64 were forwarded and spent). Hence, only fairly simple executions can follow the failed precompile calls. Therefore, we found no significantly impacted real-world contracts. None the less an advisory has been made out of an abundance of caution. There are no actions for users to take.

Record
PYSEC-2025-33
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
before 0.4.1
0.4.1
vyper
PyPI
All versions, plus listed versions
0.1.0b10.1.0b100.1.0b110.1.0b120.1.0b13
Show 45 moreShow less
0.1.0b140.1.0b150.1.0b160.1.0b170.1.0b20.1.0b30.1.0b40.1.0b50.1.0b60.1.0b70.1.0b80.1.0b90.2.10.2.100.2.110.2.120.2.130.2.140.2.150.2.160.2.20.2.30.2.40.2.50.2.60.2.70.2.80.2.90.3.00.3.10.3.100.3.10rc10.3.10rc20.3.10rc30.3.10rc40.3.10rc50.3.20.3.30.3.40.3.50.3.60.3.70.3.80.3.90.4.0
None known
vyper
PyPI
before 0.4.1, plus listed versions
0.1.0b10.1.0b100.1.0b110.1.0b120.1.0b13
Show 45 moreShow less
0.1.0b140.1.0b150.1.0b160.1.0b170.1.0b20.1.0b30.1.0b40.1.0b50.1.0b60.1.0b70.1.0b80.1.0b90.2.10.2.100.2.110.2.120.2.130.2.140.2.150.2.160.2.20.2.30.2.40.2.50.2.60.2.70.2.80.2.90.3.00.3.10.3.100.3.10rc10.3.10rc20.3.10rc30.3.10rc40.3.10rc50.3.20.3.30.3.40.3.50.3.60.3.70.3.80.3.90.4.0
0.4.1

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

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

In short

CVE-2025-21607 is a low vulnerability (CVSS 2.3) in Vyperlang Vyper, published January 14, 2025. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.67%, the 52nd percentile. Fixed in vyper 0.4.1.

References

This page doesn't list everything

Left out here: 47 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open