GHSA-2p94-8669-xg86

Suggest an improvement
Source
https://github.com/advisories/GHSA-2p94-8669-xg86
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/02/GHSA-2p94-8669-xg86/GHSA-2p94-8669-xg86.json
JSON Data
https://api.test.osv.dev/v1/vulns/GHSA-2p94-8669-xg86
Aliases
Published
2025-02-21T22:43:30Z
Modified
2025-04-09T20:32:07.986335Z
Severity
  • 2.3 (Low) CVSS_V4 - CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:L/VI:L/VA:N/SC:N/SI:N/SA:N CVSS Calculator
Summary
Vyper's sqrt doesn't define rounding behavior
Details

Vyper's sqrt() builtin uses the babylonian method to calculate square roots of decimals. Unfortunately, improper handling of the oscillating final states may lead to sqrt incorrectly returning rounded up results.

the fix is tracked in https://github.com/vyperlang/vyper/pull/4486

Vulnerability Details

Vyper injects the following code to handle calculation of decimal sqrt. x is the input provided by user.

assert x >= 0.0
z: decimal = 0.0

if x == 0.0:
    z = 0.0
else:
    z = x / 2.0 + 0.5
    y: decimal = x

    for i: uint256 in range(256):
        if z == y:
            break
        y = z
        z = (x / z + z) / 2.0

Notably, the terminal condition of the algorithm is either z_cur == z_prev, or the algorithm runs for 256 rounds.

However, for certain inputs, z might actually oscillate between N and N + epsilon, where N ** 2 <= x < (N + epsilon) ** 2. This means that the current behavior does not define whether it will round up or down to the nearest epsilon.

The example snippet here returns 0.9999999999, the rounded up result for sqrt(0.9999999998). This is due to the oscillation ending in N + epsilon instead of N.

@external
def test():
    d: decimal = 0.9999999998
    r: decimal = sqrt(d)    #this will be 0.9999999999

Note that sqrt() diverges from isqrt() here -- isqrt() consistently rounds down, so it is not subject to the same issue.

Impact Details

Since sqrt() can be used for determining boundary conditions, rounding down is preferred. However, since sqrt() is used very rarely in the wild, this advisory has been assigned an impact of low.

Database specific
{
    "severity": "LOW",
    "nvd_published_at": "2025-02-21T22:15:13Z",
    "github_reviewed": true,
    "github_reviewed_at": "2025-02-21T22:43:30Z",
    "cwe_ids": [
        "CWE-682"
    ]
}
References

Affected packages

PyPI / vyper

Package

Affected ranges

Type
ECOSYSTEM
Events
Introduced
0Unknown introduced version / All previous versions are affected
Fixed
0.4.1

Affected versions

0.*

0.1.0b1
0.1.0b2
0.1.0b3
0.1.0b4
0.1.0b5
0.1.0b6
0.1.0b7
0.1.0b8
0.1.0b9
0.1.0b10
0.1.0b11
0.1.0b12
0.1.0b13
0.1.0b14
0.1.0b15
0.1.0b16
0.1.0b17
0.2.1
0.2.2
0.2.3
0.2.4
0.2.5
0.2.6
0.2.7
0.2.8
0.2.9
0.2.10
0.2.11
0.2.12
0.2.13
0.2.14
0.2.15
0.2.16
0.3.0
0.3.1
0.3.2
0.3.3
0.3.4
0.3.5
0.3.6
0.3.7
0.3.8
0.3.9
0.3.10rc1
0.3.10rc2
0.3.10rc3
0.3.10rc4
0.3.10rc5
0.3.10
0.4.0b1
0.4.0b2
0.4.0b3
0.4.0b4
0.4.0b5
0.4.0b6
0.4.0rc1
0.4.0rc2
0.4.0rc3
0.4.0rc4
0.4.0rc5
0.4.0rc6
0.4.0
0.4.1b1
0.4.1b2
0.4.1b3
0.4.1b4
0.4.1rc1
0.4.1rc2
0.4.1rc3

Database specific

{
    "last_known_affected_version_range": "<= 0.4.0"
}