ghsa-w9g2-3w7p-72g9
Vulnerability from github
Published
2023-04-24 22:33
Modified
2024-11-19 16:31
Summary
Incorrect success value returned in vyper
Details

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: vyper 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.

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: vyper @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

Show details on source website


{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "vyper"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0.3.1"
            },
            {
              "fixed": "0.3.8"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2023-30629"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-670"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2023-04-24T22:33:52Z",
    "nvd_published_at": "2023-04-24T22:15:10Z",
    "severity": "HIGH"
  },
  "details": "### Background\nDuring the audit of [Lido\u0027s Gate Seals](https://github.com/lidofinance/gate-seals) code [statemind](https://statemind.io) team identified a weird behavior of the code that uses `raw_call`: https://github.com/lidofinance/gate-seals/blob/051593e74df01a4131c485b4fda52e691cd4b7d8/contracts/GateSeal.vy#L164 .\n\nConstruction like this:\n```vyper\nsuccess = raw_call(\n    sealable,\n    _abi_encode(SEAL_DURATION_SECONDS, method_id=method_id(\"pauseFor(uint256)\")),\n    revert_on_failure=False\n)\n```\nwas not fully documented: https://docs.vyperlang.org/en/v0.3.7/built-in-functions.html#raw_call .\n\nThe 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`.\n\n\u003cimg width=\"715\" alt=\"image\" src=\"https://user-images.githubusercontent.com/22330612/232125364-d2b3bbac-0b4f-40cb-80ff-f55d8eafef44.png\"\u003e\n\n 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:\n```\nCALL // call\nMLOAD // MLOAD is wrong since the CALL result is already stored in the stack\n```\n\n### Impact\nExample of buggy code:\n```vyper\n@external\ndef returnSome(calling: address, a: uint256) -\u003e bool:\n    success: bool = false\n    success = raw_call(\n        calling,\n        _abi_encode(a, method_id=method_id(\"a(uint256)\")),\n        revert_on_failure=False\n        )\n```\n\nany 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`.\n\n### Patches\nFix by @charles-cooper https://github.com/vyperlang/vyper/commit/851f7a1b3aa2a36fd041e3d0ed38f9355a58c8ae\n\n### Workarounds\nThe simple workaround is always to put  `max_outsize\u003e0`.\nWorkaround example https://github.com/lidofinance/gate-seals/pull/5/files\n\n### References\nLido\u0027s fix: https://github.com/lidofinance/gate-seals/pull/5/files\n",
  "id": "GHSA-w9g2-3w7p-72g9",
  "modified": "2024-11-19T16:31:34Z",
  "published": "2023-04-24T22:33:52Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/vyperlang/vyper/security/advisories/GHSA-w9g2-3w7p-72g9"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2023-30629"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lidofinance/gate-seals/pull/5/files"
    },
    {
      "type": "WEB",
      "url": "https://github.com/vyperlang/vyper/commit/851f7a1b3aa2a36fd041e3d0ed38f9355a58c8ae"
    },
    {
      "type": "WEB",
      "url": "https://docs.vyperlang.org/en/v0.3.7/built-in-functions.html#raw_call"
    },
    {
      "type": "WEB",
      "url": "https://github.com/lidofinance/gate-seals/blob/051593e74df01a4131c485b4fda52e691cd4b7d8/contracts/GateSeal.vy#L164"
    },
    {
      "type": "WEB",
      "url": "https://github.com/pypa/advisory-database/tree/main/vulns/vyper/PYSEC-2023-131.yaml"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/vyperlang/vyper"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Incorrect success value returned in vyper"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
  • Confirmed: The vulnerability is confirmed from an analyst perspective.
  • Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
  • Patched: This vulnerability was successfully patched by the user reporting the sighting.
  • Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
  • Not confirmed: The user expresses doubt about the veracity of the vulnerability.
  • Not patched: This vulnerability was not successfully patched by the user reporting the sighting.