Search

Find a vulnerability

Search criteria

    20 vulnerabilities found for hex by hexpm

    CVE-2026-96596 (GCVE-0-2026-96596)

    Vulnerability from nvd – Published: 2026-10-14 16:56 – Updated: 2026-10-14 21:46
    VLAI
    Title
    erl_tar:extract/2 loops forever on a GNU sparse member with a trailing hole
    Summary
    Loop with Unreachable Exit Condition ('Infinite Loop') vulnerability in Erlang OTP stdlib (erl_tar module), hexpm hex_core (hex_erl_tar module), hexpm hex (mix_hex_erl_tar module) and erlang rebar3 (r3_hex_erl_tar module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member. When erl_tar:extract/1,2 writes a member to disk, erl_tar:stream_to_file_loop/3 reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, erl_tar:do_sparse_read/3 matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The {max_size, N} option prevents this only when N is below the real size of the member. Extraction with the memory option is not affected. hex_core ships its own copy of erl_tar as hex_erl_tar, and Hex and rebar3 ship hex_core with prefixed module names (mix_hex_erl_tar and r3_hex_erl_tar). These copies contain the same code and do not call stdlib's erl_tar, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3. This issue affects OTP from OTP 29.0 before OTP 29.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1.
    CWE
    • CWE-835 - Loop with Unreachable Exit Condition ('Infinite Loop')
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    Erlang OTP Affected: 29.0 , < 29.1.2 (otp)
        cpe:2.3:a:erlang:erlang\/otp:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Erlang OTP Affected: 8.0 , < 8.1.1 (otp)
        cpe:2.3:a:erlang:erlang\/otp:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Erlang OTP Affected: fbf2c7194f6fce4b7b66dc0bcaa4f6b4b85e088f , < 3086307f311b78b38644a7787a3aca6a3f95a9d5 (git)
        cpe:2.3:a:erlang:erlang\/otp:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 3.27.1 , < * (semver)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 23dbdb5d1f87f56902aef296c88a20049cd0c6e4 , < * (git)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 0.14.0 , < 0.20.1 (semver)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 13bb9fbba418a406af614790b8d5cd458259ee70 , < a2ece683e6e88a3ec95ad20b09aca426e08b372e (git)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 2.4.2 , < 2.5.3 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 5543a1919c709d8eb2b317f62aad76ca1eed375c , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Date Public
    2026-10-14 16:56
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "erl_tar"
              ],
              "packageName": "otp",
              "packageURL": "pkg:software-id/erlang.org/otp",
              "product": "OTP",
              "programFiles": [
                "lib/stdlib/src/erl_tar.erl"
              ],
              "programRoutines": [
                {
                  "name": "erl_tar:do_sparse_read/3"
                },
                {
                  "name": "erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "erl_tar:extract/1"
                },
                {
                  "name": "erl_tar:extract/2"
                }
              ],
              "vendor": "Erlang",
              "versions": [
                {
                  "lessThan": "29.1.2",
                  "status": "affected",
                  "version": "29.0",
                  "versionType": "otp"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "erl_tar"
              ],
              "packageName": "stdlib",
              "packageURL": "pkg:otp/stdlib?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Fotp\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Fotp.git",
              "product": "OTP",
              "programFiles": [
                "src/erl_tar.erl"
              ],
              "programRoutines": [
                {
                  "name": "erl_tar:do_sparse_read/3"
                },
                {
                  "name": "erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "erl_tar:extract/1"
                },
                {
                  "name": "erl_tar:extract/2"
                }
              ],
              "repo": "https://github.com/erlang/otp",
              "vendor": "Erlang",
              "versions": [
                {
                  "lessThan": "8.1.1",
                  "status": "affected",
                  "version": "8.0",
                  "versionType": "otp"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "erl_tar"
              ],
              "packageName": "erlang/otp",
              "packageURL": "pkg:github/erlang/otp",
              "product": "OTP",
              "programFiles": [
                "lib/stdlib/src/erl_tar.erl"
              ],
              "programRoutines": [
                {
                  "name": "erl_tar:do_sparse_read/3"
                },
                {
                  "name": "erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "erl_tar:extract/1"
                },
                {
                  "name": "erl_tar:extract/2"
                }
              ],
              "repo": "https://github.com/erlang/otp",
              "vendor": "Erlang",
              "versions": [
                {
                  "lessThan": "3086307f311b78b38644a7787a3aca6a3f95a9d5",
                  "status": "affected",
                  "version": "fbf2c7194f6fce4b7b66dc0bcaa4f6b4b85e088f",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_erl_tar",
                "r3_hex_tarball"
              ],
              "packageName": "rebar3",
              "packageURL": "pkg:otp/rebar3?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Frebar3\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Frebar3.git",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_erl_tar.erl",
                "apps/rebar/src/vendored/r3_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "r3_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "r3_hex_erl_tar:extract/1"
                },
                {
                  "name": "r3_hex_erl_tar:extract/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/3"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "*",
                  "status": "affected",
                  "version": "3.27.1",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_erl_tar",
                "r3_hex_tarball"
              ],
              "packageName": "erlang/rebar3",
              "packageURL": "pkg:github/erlang/rebar3",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_erl_tar.erl",
                "apps/rebar/src/vendored/r3_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "r3_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "r3_hex_erl_tar:extract/1"
                },
                {
                  "name": "r3_hex_erl_tar:extract/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/3"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "*",
                  "status": "affected",
                  "version": "23dbdb5d1f87f56902aef296c88a20049cd0c6e4",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_erl_tar",
                "hex_tarball"
              ],
              "packageName": "hex_core",
              "packageURL": "pkg:hex/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_erl_tar.erl",
                "src/hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "hex_erl_tar:extract/1"
                },
                {
                  "name": "hex_erl_tar:extract/2"
                },
                {
                  "name": "hex_tarball:unpack/2"
                },
                {
                  "name": "hex_tarball:unpack/3"
                },
                {
                  "name": "hex_tarball:unpack_docs/2"
                },
                {
                  "name": "hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "0.20.1",
                  "status": "affected",
                  "version": "0.14.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_erl_tar",
                "hex_tarball"
              ],
              "packageName": "hexpm/hex_core",
              "packageURL": "pkg:github/hexpm/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_erl_tar.erl",
                "src/hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "hex_erl_tar:extract/1"
                },
                {
                  "name": "hex_erl_tar:extract/2"
                },
                {
                  "name": "hex_tarball:unpack/2"
                },
                {
                  "name": "hex_tarball:unpack/3"
                },
                {
                  "name": "hex_tarball:unpack_docs/2"
                },
                {
                  "name": "hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "a2ece683e6e88a3ec95ad20b09aca426e08b372e",
                  "status": "affected",
                  "version": "13bb9fbba418a406af614790b8d5cd458259ee70",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_erl_tar",
                "mix_hex_tarball"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_erl_tar.erl",
                "src/mix_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "mix_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "mix_hex_erl_tar:extract/1"
                },
                {
                  "name": "mix_hex_erl_tar:extract/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/3"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.3",
                  "status": "affected",
                  "version": "2.4.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_erl_tar",
                "mix_hex_tarball"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_erl_tar.erl",
                "src/mix_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "mix_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "mix_hex_erl_tar:extract/1"
                },
                {
                  "name": "mix_hex_erl_tar:extract/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/3"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "8e1067131a13949eff30623f31648a945ffd5418",
                      "status": "unaffected"
                    },
                    {
                      "at": "7847c23d09ab52113614c3718e1e7d368743da5d",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "5543a1919c709d8eb2b317f62aad76ca1eed375c",
                  "versionType": "git"
                }
              ]
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "29.1.2",
                      "versionStartIncluding": "29.0",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*",
                      "versionStartIncluding": "3.27.1",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.20.1",
                      "versionStartIncluding": "0.14.0",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.3",
                      "versionStartIncluding": "2.4.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "reporter",
              "value": "Eric Meadows-J\u00f6nsson"
            }
          ],
          "dateAssigned": "2026-10-07T13:11:38.000Z",
          "datePublic": "2026-10-14T16:56:18.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eLoop with Unreachable Exit Condition (\u0027Infinite Loop\u0027) vulnerability in Erlang OTP stdlib (\u003ccode\u003eerl_tar\u003c/code\u003e module), hexpm hex_core (\u003ccode\u003ehex_erl_tar\u003c/code\u003e module), hexpm hex (\u003ccode\u003emix_hex_erl_tar\u003c/code\u003e module) and erlang rebar3 (\u003ccode\u003er3_hex_erl_tar\u003c/code\u003e module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member.\u003c/p\u003e\n\u003cp\u003eWhen \u003ccode\u003eerl_tar:extract/1,2\u003c/code\u003e writes a member to disk, \u003ccode\u003eerl_tar:stream_to_file_loop/3\u003c/code\u003e reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, \u003ccode\u003eerl_tar:do_sparse_read/3\u003c/code\u003e matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The \u003ccode\u003e{max_size, N}\u003c/code\u003e option prevents this only when N is below the real size of the member. Extraction with the \u003ccode\u003ememory\u003c/code\u003e option is not affected.\u003c/p\u003e\n\u003cp\u003ehex_core ships its own copy of \u003ccode\u003eerl_tar\u003c/code\u003e as \u003ccode\u003ehex_erl_tar\u003c/code\u003e, and Hex and rebar3 ship hex_core with prefixed module names (\u003ccode\u003emix_hex_erl_tar\u003c/code\u003e and \u003ccode\u003er3_hex_erl_tar\u003c/code\u003e). These copies contain the same code and do not call stdlib\u0027s \u003ccode\u003eerl_tar\u003c/code\u003e, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3.\u003c/p\u003e\n\u003cp\u003eThis issue affects OTP from OTP\u0026nbsp;29.0 before OTP\u0026nbsp;29.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027) vulnerability in Erlang OTP stdlib (`erl_tar` module), hexpm hex_core (`hex_erl_tar` module), hexpm hex (`mix_hex_erl_tar` module) and erlang rebar3 (`r3_hex_erl_tar` module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member.\n\nWhen `erl_tar:extract/1,2` writes a member to disk, `erl_tar:stream_to_file_loop/3` reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, `erl_tar:do_sparse_read/3` matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The `{max_size, N}` option prevents this only when N is below the real size of the member. Extraction with the `memory` option is not affected.\n\nhex_core ships its own copy of `erl_tar` as `hex_erl_tar`, and Hex and rebar3 ship hex_core with prefixed module names (`mix_hex_erl_tar` and `r3_hex_erl_tar`). These copies contain the same code and do not call stdlib\u0027s `erl_tar`, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3.\n\nThis issue affects OTP from OTP\u00a029.0 before OTP\u00a029.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1."
                }
              ],
              "value": "Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027) vulnerability in Erlang OTP stdlib (erl_tar module), hexpm hex_core (hex_erl_tar module), hexpm hex (mix_hex_erl_tar module) and erlang rebar3 (r3_hex_erl_tar module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member.\n\nWhen erl_tar:extract/1,2 writes a member to disk, erl_tar:stream_to_file_loop/3 reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, erl_tar:do_sparse_read/3 matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The {max_size, N} option prevents this only when N is below the real size of the member. Extraction with the memory option is not affected.\n\nhex_core ships its own copy of erl_tar as hex_erl_tar, and Hex and rebar3 ship hex_core with prefixed module names (mix_hex_erl_tar and r3_hex_erl_tar). These copies contain the same code and do not call stdlib\u0027s erl_tar, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3.\n\nThis issue affects OTP from OTP\u00a029.0 before OTP\u00a029.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eAn attacker who can get an application to extract a tar archive to disk keeps the extracting process and one scheduler busy forever. Each further archive occupies another scheduler, until the node stops responding.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "An attacker who can get an application to extract a tar archive to disk keeps the extracting process and one scheduler busy forever. Each further archive occupies another scheduler, until the node stops responding."
                    }
                  ],
                  "value": "An attacker who can get an application to extract a tar archive to disk keeps the extracting process and one scheduler busy forever. Each further archive occupies another scheduler, until the node stops responding."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "LOCAL",
                "baseScore": 5.9,
                "baseSeverity": "MEDIUM",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "NONE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-835",
                  "description": "CWE-835 Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-14T21:46:30.112Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/erlang/otp/security/advisories/GHSA-phm5-m6cj-5382"
            },
            {
              "name": "EEF CNA record for CVE-2026-96596",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-96596.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-96596",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-96596"
            },
            {
              "name": "Erlang/OTP version ordering",
              "tags": [
                "x_version-scheme"
              ],
              "url": "https://www.erlang.org/doc/system/versions.html#order-of-versions"
            },
            {
              "name": "Introducing commit fbf2c71 in erlang/otp",
              "tags": [
                "related"
              ],
              "url": "https://github.com/erlang/otp/commit/fbf2c7194f6fce4b7b66dc0bcaa4f6b4b85e088f"
            },
            {
              "name": "Fix commit 3086307 in erlang/otp",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/erlang/otp/commit/3086307f311b78b38644a7787a3aca6a3f95a9d5"
            },
            {
              "name": "Introducing commit 23dbdb5 in erlang/rebar3",
              "tags": [
                "related"
              ],
              "url": "https://github.com/erlang/rebar3/commit/23dbdb5d1f87f56902aef296c88a20049cd0c6e4"
            },
            {
              "name": "Introducing commit 13bb9fb in hexpm/hex_core",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/13bb9fbba418a406af614790b8d5cd458259ee70"
            },
            {
              "name": "Fix commit a2ece68 in hexpm/hex_core",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/a2ece683e6e88a3ec95ad20b09aca426e08b372e"
            },
            {
              "name": "Introducing commit 5543a19 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/5543a1919c709d8eb2b317f62aad76ca1eed375c"
            },
            {
              "name": "Fix commit 8e10671 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/8e1067131a13949eff30623f31648a945ffd5418"
            },
            {
              "name": "Fix commit 7847c23 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/7847c23d09ab52113614c3718e1e7d368743da5d"
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "erl_tar:extract/2 loops forever on a GNU sparse member with a trailing hole",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003ePass \u003ccode\u003e{chunks, N}\u003c/code\u003e together with \u003ccode\u003e{max_size, N}\u003c/code\u003e, with the same value N, to \u003ccode\u003eerl_tar:extract/2\u003c/code\u003e. Extraction then rejects any member larger than N, and reads each remaining member in one call, so the loop cannot occur.\u003c/p\u003e\n\u003cp\u003eAlternatively, extract with the \u003ccode\u003ememory\u003c/code\u003e option and write the returned files to disk in the application.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Pass `{chunks, N}` together with `{max_size, N}`, with the same value N, to `erl_tar:extract/2`. Extraction then rejects any member larger than N, and reads each remaining member in one call, so the loop cannot occur.\n\nAlternatively, extract with the `memory` option and write the returned files to disk in the application."
                }
              ],
              "value": "Pass {chunks, N} together with {max_size, N}, with the same value N, to erl_tar:extract/2. Extraction then rejects any member larger than N, and reads each remaining member in one call, so the loop cannot occur.\n\nAlternatively, extract with the memory option and write the returned files to disk in the application."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eBuild a 2048-byte tar that holds one GNU sparse member (typeflag \u003ccode\u003eS\u003c/code\u003e). Give it a stored size of 4 bytes, one sparse map entry of 4 bytes at offset 0, and a real size of 1048576 bytes. Follow the 512-byte header with a 512-byte block that starts with the 4 data bytes, then 1024 zero bytes.\u003c/li\u003e\n\u003cli\u003eIn a separate process, call \u003ccode\u003eerl_tar:extract({binary, Tar}, [{cwd, Dir}])\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe call does not return. After 5 seconds the process has used more than 10^9 reductions. On OTP 28 the same call returns \u003ccode\u003eok\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Build a 2048-byte tar that holds one GNU sparse member (typeflag `S`). Give it a stored size of 4 bytes, one sparse map entry of 4 bytes at offset 0, and a real size of 1048576 bytes. Follow the 512-byte header with a 512-byte block that starts with the 4 data bytes, then 1024 zero bytes.\n2. In a separate process, call `erl_tar:extract({binary, Tar}, [{cwd, Dir}])`.\n3. The call does not return. After 5 seconds the process has used more than 10^9 reductions. On OTP 28 the same call returns `ok`."
                }
              ],
              "value": "* Build a 2048-byte tar that holds one GNU sparse member (typeflag S). Give it a stored size of 4 bytes, one sparse map entry of 4 bytes at offset 0, and a real size of 1048576 bytes. Follow the 512-byte header with a 512-byte block that starts with the 4 data bytes, then 1024 zero bytes.\n* In a separate process, call erl_tar:extract({binary, Tar}, [{cwd, Dir}]).\n* The call does not return. After 5 seconds the process has used more than 10^9 reductions. On OTP 28 the same call returns ok."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003e\u003cstrong\u003e1. Chunked extraction.\u003c/strong\u003e \u003ccode\u003eerl_tar:extract/2\u003c/code\u003e writes each member to disk through \u003ccode\u003estream_to_file_loop/3\u003c/code\u003e. This function calls \u003ccode\u003edo_read(Reader, ChunkSize)\u003c/code\u003e until the \u003ccode\u003enum_bytes\u003c/code\u003e field of the reader is 0. The default chunk size is 65536 bytes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. Clause order in \u003ccode\u003edo_sparse_read/3\u003c/code\u003e.\u003c/strong\u003e For a sparse member, \u003ccode\u003edo_read/2\u003c/code\u003e calls \u003ccode\u003edo_sparse_read/3\u003c/code\u003e. The clause for a trailing hole matches when \u003ccode\u003esparse_map\u003c/code\u003e is \u003ccode\u003e[]\u003c/code\u003e and \u003ccode\u003ePos \u0026lt; Size\u003c/code\u003e. It comes before the clause that returns when \u003ccode\u003eLen\u003c/code\u003e is 0.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. Unbounded recursion.\u003c/strong\u003e The member is a GNU sparse member (typeflag \u003ccode\u003eS\u003c/code\u003e) whose real size is larger than one chunk and whose sparse map ends before the real size. After the data fragments, the trailing-hole clause reads the rest of the chunk and recurses with \u003ccode\u003eLen = 0\u003c/code\u003e. The same clause matches again, and \u003ccode\u003eread_sparse_hole/3\u003c/code\u003e returns an empty binary and leaves \u003ccode\u003ePos\u003c/code\u003e unchanged. The zero-length clause is never reached, so the call never returns.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. No mitigation from \u003ccode\u003emax_size\u003c/code\u003e.\u003c/strong\u003e For a sparse member, \u003ccode\u003e{max_size, N}\u003c/code\u003e is checked against the real size from the header. It stops the loop only when N is below that size. \u003ccode\u003eerl_tar:table/2\u003c/code\u003e lists the member as \u003ccode\u003eregular\u003c/code\u003e, so a caller cannot skip sparse members by type.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "**1. Chunked extraction.** `erl_tar:extract/2` writes each member to disk through `stream_to_file_loop/3`. This function calls `do_read(Reader, ChunkSize)` until the `num_bytes` field of the reader is 0. The default chunk size is 65536 bytes.\n\n**2. Clause order in `do_sparse_read/3`.** For a sparse member, `do_read/2` calls `do_sparse_read/3`. The clause for a trailing hole matches when `sparse_map` is `[]` and `Pos \u003c Size`. It comes before the clause that returns when `Len` is 0.\n\n**3. Unbounded recursion.** The member is a GNU sparse member (typeflag `S`) whose real size is larger than one chunk and whose sparse map ends before the real size. After the data fragments, the trailing-hole clause reads the rest of the chunk and recurses with `Len = 0`. The same clause matches again, and `read_sparse_hole/3` returns an empty binary and leaves `Pos` unchanged. The zero-length clause is never reached, so the call never returns.\n\n**4. No mitigation from `max_size`.** For a sparse member, `{max_size, N}` is checked against the real size from the header. It stops the loop only when N is below that size. `erl_tar:table/2` lists the member as `regular`, so a caller cannot skip sparse members by type."
                }
              ],
              "value": "1. Chunked extraction. erl_tar:extract/2 writes each member to disk through stream_to_file_loop/3. This function calls do_read(Reader, ChunkSize) until the num_bytes field of the reader is 0. The default chunk size is 65536 bytes.\n\n2. Clause order in do_sparse_read/3. For a sparse member, do_read/2 calls do_sparse_read/3. The clause for a trailing hole matches when sparse_map is [] and Pos \u003c Size. It comes before the clause that returns when Len is 0.\n\n3. Unbounded recursion. The member is a GNU sparse member (typeflag S) whose real size is larger than one chunk and whose sparse map ends before the real size. After the data fragments, the trailing-hole clause reads the rest of the chunk and recurses with Len = 0. The same clause matches again, and read_sparse_hole/3 returns an empty binary and leaves Pos unchanged. The zero-length clause is never reached, so the call never returns.\n\n4. No mitigation from max_size. For a sparse member, {max_size, N} is checked against the real size from the header. It stops the loop only when N is below that size. erl_tar:table/2 lists the member as regular, so a caller cannot skip sparse members by type."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-96596",
        "datePublished": "2026-10-14T16:56:18.530Z",
        "dateReserved": "2026-09-27T12:00:01.540Z",
        "dateUpdated": "2026-10-14T21:46:30.112Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-105274 (GCVE-0-2026-105274)

    Vulnerability from nvd – Published: 2026-10-12 16:43 – Updated: 2026-10-15 18:05
    VLAI
    Title
    hex_core decompresses registry and Erlang term API responses without size limits
    Summary
    Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core's API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (mix_hex_repo, mix_hex_api) and rebar3 (r3_hex_repo, r3_hex_api). hex_repo:get_names/1, hex_repo:get_versions/1, hex_repo:get_package/2 and hex_repo:get_policy/2 decompress the registry response with zlib:gunzip/1 and decode the signed envelope before verifying its signature. A mirror doesn't have the repository's private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it. hex_api decodes responses with the application/vnd.hex+erlang content type through hex_safe_binary_to_term:safe_binary_to_term/1, which calls binary_to_term(Binary, [safe]). The safe option prevents atom creation, but it accepts compressed terms and doesn't limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the safe option and that check without bounding the decoded size. This issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0.
    SSVC
    Exploitation: none Automatable: no Technical Impact: partial
    CISA Coordinator · CISA-ADP (v2.0.3)
    Decision recorded 2026-10-15 17:51 UTC
    CWE
    • CWE-409 - Improper Handling of Highly Compressed Data (Data Amplification)
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    erlang rebar3 Affected: 3.9.1 , < 3.27.3 (semver)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 209c02ec57c2cc3207ee0174c3af3675b8dc8f79 , < 360838a22f5b3a88c0358207f2923059bcbb3afb (git)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 0.1.0 , < 0.20.0 (semver)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: fbb6d9de472e5edb8d6fb6b32a91cb266137892e , < ebe25d110717f6a3addba5232cd4a7dc1c76b628 (git)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 2.1.0 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 671f695ac548ed01f5828c2a739ecaa942b21007 , < d8b60eee97abb119d525306f048969a217d793a5 (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Date Public
    2026-10-12 16:43
    Show details on NVD website

    {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-105274",
                    "options": [
                      {
                        "Exploitation": "none"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "partial"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-10-15T17:51:41.556015Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-10-15T18:05:12.446Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_repo",
                "r3_hex_api"
              ],
              "packageName": "rebar3",
              "packageURL": "pkg:otp/rebar3?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Frebar3\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Frebar3.git",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_repo.erl",
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_repo:get_names/1"
                },
                {
                  "name": "r3_hex_repo:get_versions/1"
                },
                {
                  "name": "r3_hex_repo:get_package/2"
                },
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "3.27.3",
                  "status": "affected",
                  "version": "3.9.1",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_repo",
                "r3_hex_api"
              ],
              "packageName": "erlang/rebar3",
              "packageURL": "pkg:github/erlang/rebar3",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_repo.erl",
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_repo:get_names/1"
                },
                {
                  "name": "r3_hex_repo:get_versions/1"
                },
                {
                  "name": "r3_hex_repo:get_package/2"
                },
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "360838a22f5b3a88c0358207f2923059bcbb3afb",
                  "status": "affected",
                  "version": "209c02ec57c2cc3207ee0174c3af3675b8dc8f79",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_repo",
                "hex_api",
                "hex_safe_binary_to_term"
              ],
              "packageName": "hex_core",
              "packageURL": "pkg:hex/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_repo.erl",
                "src/hex_api.erl",
                "src/hex_safe_binary_to_term.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_repo:get_names/1"
                },
                {
                  "name": "hex_repo:get_versions/1"
                },
                {
                  "name": "hex_repo:get_package/2"
                },
                {
                  "name": "hex_repo:get_policy/2"
                },
                {
                  "name": "hex_api:request/4"
                },
                {
                  "name": "hex_safe_binary_to_term:safe_binary_to_term/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "0.20.0",
                  "status": "affected",
                  "version": "0.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_repo",
                "hex_api",
                "hex_safe_binary_to_term"
              ],
              "packageName": "hexpm/hex_core",
              "packageURL": "pkg:github/hexpm/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_repo.erl",
                "src/hex_api.erl",
                "src/hex_safe_binary_to_term.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_repo:get_names/1"
                },
                {
                  "name": "hex_repo:get_versions/1"
                },
                {
                  "name": "hex_repo:get_package/2"
                },
                {
                  "name": "hex_repo:get_policy/2"
                },
                {
                  "name": "hex_api:request/4"
                },
                {
                  "name": "hex_safe_binary_to_term:safe_binary_to_term/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "ebe25d110717f6a3addba5232cd4a7dc1c76b628",
                  "status": "affected",
                  "version": "fbb6d9de472e5edb8d6fb6b32a91cb266137892e",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_repo",
                "mix_hex_api"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_repo.erl",
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_repo:get_names/1"
                },
                {
                  "name": "mix_hex_repo:get_versions/1"
                },
                {
                  "name": "mix_hex_repo:get_package/2"
                },
                {
                  "name": "mix_hex_repo:get_policy/2"
                },
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "2.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_repo",
                "mix_hex_api"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_repo.erl",
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_repo:get_names/1"
                },
                {
                  "name": "mix_hex_repo:get_versions/1"
                },
                {
                  "name": "mix_hex_repo:get_package/2"
                },
                {
                  "name": "mix_hex_repo:get_policy/2"
                },
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "d8b60eee97abb119d525306f048969a217d793a5",
                  "status": "affected",
                  "version": "671f695ac548ed01f5828c2a739ecaa942b21007",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eRegistry decoding is affected when a repository\u0027s URL points at a mirror or another server the user doesn\u0027t trust with the availability of their builds, for example Hex\u0027s \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e and rebar3\u0027s \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e. API decoding is affected when the API URL points at such a server or an attacker can alter API responses. Requests to repo.hex.pm and hex.pm over verified HTTPS aren\u0027t affected.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Registry decoding is affected when a repository\u0027s URL points at a mirror or another server the user doesn\u0027t trust with the availability of their builds, for example Hex\u0027s `HEX_MIRROR_URL` or `mirror_url` and rebar3\u0027s `HEX_MIRROR_URL`. API decoding is affected when the API URL points at such a server or an attacker can alter API responses. Requests to repo.hex.pm and hex.pm over verified HTTPS aren\u0027t affected."
                }
              ],
              "value": "Registry decoding is affected when a repository\u0027s URL points at a mirror or another server the user doesn\u0027t trust with the availability of their builds, for example Hex\u0027s HEX_MIRROR_URL or mirror_url and rebar3\u0027s HEX_MIRROR_URL. API decoding is affected when the API URL points at such a server or an attacker can alter API responses. Requests to repo.hex.pm and hex.pm over verified HTTPS aren\u0027t affected."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "3.27.3",
                      "versionStartIncluding": "3.9.1",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.20.0",
                      "versionStartIncluding": "0.1.0",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "2.1.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:01:00.000Z",
          "datePublic": "2026-10-12T16:43:59.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core\u0027s API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (\u003ccode\u003emix_hex_repo\u003c/code\u003e, \u003ccode\u003emix_hex_api\u003c/code\u003e) and rebar3 (\u003ccode\u003er3_hex_repo\u003c/code\u003e, \u003ccode\u003er3_hex_api\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehex_repo:get_names/1\u003c/code\u003e, \u003ccode\u003ehex_repo:get_versions/1\u003c/code\u003e, \u003ccode\u003ehex_repo:get_package/2\u003c/code\u003e and \u003ccode\u003ehex_repo:get_policy/2\u003c/code\u003e decompress the registry response with \u003ccode\u003ezlib:gunzip/1\u003c/code\u003e and decode the signed envelope before verifying its signature. A mirror doesn\u0027t have the repository\u0027s private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehex_api\u003c/code\u003e decodes responses with the \u003ccode\u003eapplication/vnd.hex+erlang\u003c/code\u003e content type through \u003ccode\u003ehex_safe_binary_to_term:safe_binary_to_term/1\u003c/code\u003e, which calls \u003ccode\u003ebinary_to_term(Binary, [safe])\u003c/code\u003e. The \u003ccode\u003esafe\u003c/code\u003e option prevents atom creation, but it accepts compressed terms and doesn\u0027t limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the \u003ccode\u003esafe\u003c/code\u003e option and that check without bounding the decoded size.\u003c/p\u003e\n\u003cp\u003eThis issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core\u0027s API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (`mix_hex_repo`, `mix_hex_api`) and rebar3 (`r3_hex_repo`, `r3_hex_api`).\n\n`hex_repo:get_names/1`, `hex_repo:get_versions/1`, `hex_repo:get_package/2` and `hex_repo:get_policy/2` decompress the registry response with `zlib:gunzip/1` and decode the signed envelope before verifying its signature. A mirror doesn\u0027t have the repository\u0027s private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it.\n\n`hex_api` decodes responses with the `application/vnd.hex+erlang` content type through `hex_safe_binary_to_term:safe_binary_to_term/1`, which calls `binary_to_term(Binary, [safe])`. The `safe` option prevents atom creation, but it accepts compressed terms and doesn\u0027t limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the `safe` option and that check without bounding the decoded size.\n\nThis issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0."
                }
              ],
              "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core\u0027s API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (mix_hex_repo, mix_hex_api) and rebar3 (r3_hex_repo, r3_hex_api).\n\nhex_repo:get_names/1, hex_repo:get_versions/1, hex_repo:get_package/2 and hex_repo:get_policy/2 decompress the registry response with zlib:gunzip/1 and decode the signed envelope before verifying its signature. A mirror doesn\u0027t have the repository\u0027s private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it.\n\nhex_api decodes responses with the application/vnd.hex+erlang content type through hex_safe_binary_to_term:safe_binary_to_term/1, which calls binary_to_term(Binary, [safe]). The safe option prevents atom creation, but it accepts compressed terms and doesn\u0027t limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the safe option and that check without bounding the decoded size.\n\nThis issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA mirror can make every registry fetch allocate memory far beyond the size of its response: in a test against Hex main 851b938, which vendors this code, a 65 KB registry response decompressed into a 64 MiB envelope before the signature check failed. The API server, or an attacker who can alter its responses, can do the same with API responses: 8 KB of compressed Erlang term format decoded into a list of 4.2 million elements. Large enough responses stop the Erlang VM, which fails the build tool command or the program using hex_core. No package code has to run.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A mirror can make every registry fetch allocate memory far beyond the size of its response: in a test against Hex main 851b938, which vendors this code, a 65 KB registry response decompressed into a 64 MiB envelope before the signature check failed. The API server, or an attacker who can alter its responses, can do the same with API responses: 8 KB of compressed Erlang term format decoded into a list of 4.2 million elements. Large enough responses stop the Erlang VM, which fails the build tool command or the program using hex_core. No package code has to run."
                    }
                  ],
                  "value": "A mirror can make every registry fetch allocate memory far beyond the size of its response: in a test against Hex main 851b938, which vendors this code, a 65 KB registry response decompressed into a 64 MiB envelope before the signature check failed. The API server, or an attacker who can alter its responses, can do the same with API responses: 8 KB of compressed Erlang term format decoded into a list of 4.2 million elements. Large enough responses stop the Erlang VM, which fails the build tool command or the program using hex_core. No package code has to run."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2.1,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "LOW",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-409",
                  "description": "CWE-409 Improper Handling of Highly Compressed Data (Data Amplification)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T18:16:57.155Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq"
            },
            {
              "name": "EEF CNA record for CVE-2026-105274",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-105274.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-105274",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-105274"
            },
            {
              "name": "Introducing commit 209c02e in erlang/rebar3",
              "tags": [
                "related"
              ],
              "url": "https://github.com/erlang/rebar3/commit/209c02ec57c2cc3207ee0174c3af3675b8dc8f79"
            },
            {
              "name": "Fix commit 360838a in erlang/rebar3",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/erlang/rebar3/commit/360838a22f5b3a88c0358207f2923059bcbb3afb"
            },
            {
              "name": "Introducing commit fbb6d9d in hexpm/hex_core",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/fbb6d9de472e5edb8d6fb6b32a91cb266137892e"
            },
            {
              "name": "Fix commit ebe25d1 in hexpm/hex_core",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/ebe25d110717f6a3addba5232cd4a7dc1c76b628"
            },
            {
              "name": "Introducing commit 671f695 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/671f695ac548ed01f5828c2a739ecaa942b21007"
            },
            {
              "name": "Fix commit d8b60ee in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/d8b60eee97abb119d525306f048969a217d793a5"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade hex_core to 0.20.0 or later. Registry resources larger than 16 MiB after decompression are rejected with \u003ccode\u003e{too_big_uncompressed, MaxSize}\u003c/code\u003e, configurable with \u003ccode\u003eregistry_max_uncompressed_size\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eUpgrade Hex to 2.5.2 or later, which vendors hex_core 0.20.0. No rebar3 release vendors hex_core 0.20.0 yet.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade hex_core to 0.20.0 or later. Registry resources larger than 16 MiB after decompression are rejected with `{too_big_uncompressed, MaxSize}`, configurable with `registry_max_uncompressed_size`.\n\nUpgrade Hex to 2.5.2 or later, which vendors hex_core 0.20.0. No rebar3 release vendors hex_core 0.20.0 yet."
                }
              ],
              "value": "Upgrade hex_core to 0.20.0 or later. Registry resources larger than 16 MiB after decompression are rejected with {too_big_uncompressed, MaxSize}, configurable with registry_max_uncompressed_size.\n\nUpgrade Hex to 2.5.2 or later, which vendors hex_core 0.20.0. No rebar3 release vendors hex_core 0.20.0 yet."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "hex_core decompresses registry and Erlang term API responses without size limits",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003ePoint repository URLs at repo.hex.pm or a mirror you operate, and the API URL at hex.pm.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Point repository URLs at repo.hex.pm or a mirror you operate, and the API URL at hex.pm."
                }
              ],
              "value": "Point repository URLs at repo.hex.pm or a mirror you operate, and the API URL at hex.pm."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003ePoint a repository at a loopback mirror (in Hex, \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e) that answers \u003ccode\u003e/packages/probe\u003c/code\u003e with a 65,268-byte gzip stream decompressing to a 67,108,872-byte signed envelope with a 64 MiB payload and a one-byte signature.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.Repo.get_package(\"hexpm\", \"probe\", nil)\u003c/code\u003e, which calls the vendored \u003ccode\u003ehex_repo:get_package/2\u003c/code\u003e, returns \u003ccode\u003e{:error, :bad_signature}\u003c/code\u003e after allocating the envelope. Peak RSS was 234 MiB, against 96 MiB for a 1,030-byte invalid envelope.\u003c/li\u003e\n\u003cli\u003eAnswer an API request with \u003ccode\u003econtent-type: application/vnd.hex+erlang\u003c/code\u003e and 8,178 bytes of compressed Erlang term format encoding a list of 4,194,304 elements. \u003ccode\u003emix_hex_api:get/2\u003c/code\u003e accepts the decoded term, and BEAM memory rises from 58 MiB to 272 MiB.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Point a repository at a loopback mirror (in Hex, `HEX_MIRROR_URL`) that answers `/packages/probe` with a 65,268-byte gzip stream decompressing to a 67,108,872-byte signed envelope with a 64 MiB payload and a one-byte signature.\n2. `Hex.Repo.get_package(\"hexpm\", \"probe\", nil)`, which calls the vendored `hex_repo:get_package/2`, returns `{:error, :bad_signature}` after allocating the envelope. Peak RSS was 234 MiB, against 96 MiB for a 1,030-byte invalid envelope.\n3. Answer an API request with `content-type: application/vnd.hex+erlang` and 8,178 bytes of compressed Erlang term format encoding a list of 4,194,304 elements. `mix_hex_api:get/2` accepts the decoded term, and BEAM memory rises from 58 MiB to 272 MiB."
                }
              ],
              "value": "* Point a repository at a loopback mirror (in Hex, HEX_MIRROR_URL) that answers /packages/probe with a 65,268-byte gzip stream decompressing to a 67,108,872-byte signed envelope with a 64 MiB payload and a one-byte signature.\n* Hex.Repo.get_package(\"hexpm\", \"probe\", nil), which calls the vendored hex_repo:get_package/2, returns {:error, :bad_signature} after allocating the envelope. Peak RSS was 234 MiB, against 96 MiB for a 1,030-byte invalid envelope.\n* Answer an API request with content-type: application/vnd.hex+erlang and 8,178 bytes of compressed Erlang term format encoding a list of 4,194,304 elements. mix_hex_api:get/2 accepts the decoded term, and BEAM memory rises from 58 MiB to 272 MiB."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003ehex_repo:get_protobuf/3\u003c/code\u003e, used by \u003ccode\u003eget_names/1\u003c/code\u003e, \u003ccode\u003eget_versions/1\u003c/code\u003e, \u003ccode\u003eget_package/2\u003c/code\u003e and \u003ccode\u003eget_policy/2\u003c/code\u003e, calls \u003ccode\u003ezlib:gunzip/1\u003c/code\u003e on the whole response body with no output limit.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehex_repo:decode/4\u003c/code\u003e then calls \u003ccode\u003ehex_registry:decode_and_verify_signed/2\u003c/code\u003e, which decodes the protobuf envelope, copying its payload and signature, before checking the signature.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehex_api:request/4\u003c/code\u003e passes every response whose content type contains \u003ccode\u003eapplication/vnd.hex+erlang\u003c/code\u003e to \u003ccode\u003ehex_safe_binary_to_term:safe_binary_to_term/1\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esafe_binary_to_term/1\u003c/code\u003e calls \u003ccode\u003ebinary_to_term(Binary, [safe])\u003c/code\u003e, which decompresses compressed terms and builds the whole term, and only then walks it to reject functions and ports.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `hex_repo:get_protobuf/3`, used by `get_names/1`, `get_versions/1`, `get_package/2` and `get_policy/2`, calls `zlib:gunzip/1` on the whole response body with no output limit.\n2. `hex_repo:decode/4` then calls `hex_registry:decode_and_verify_signed/2`, which decodes the protobuf envelope, copying its payload and signature, before checking the signature.\n3. `hex_api:request/4` passes every response whose content type contains `application/vnd.hex+erlang` to `hex_safe_binary_to_term:safe_binary_to_term/1`.\n4. `safe_binary_to_term/1` calls `binary_to_term(Binary, [safe])`, which decompresses compressed terms and builds the whole term, and only then walks it to reject functions and ports."
                }
              ],
              "value": "* hex_repo:get_protobuf/3, used by get_names/1, get_versions/1, get_package/2 and get_policy/2, calls zlib:gunzip/1 on the whole response body with no output limit.\n* hex_repo:decode/4 then calls hex_registry:decode_and_verify_signed/2, which decodes the protobuf envelope, copying its payload and signature, before checking the signature.\n* hex_api:request/4 passes every response whose content type contains application/vnd.hex+erlang to hex_safe_binary_to_term:safe_binary_to_term/1.\n* safe_binary_to_term/1 calls binary_to_term(Binary, [safe]), which decompresses compressed terms and builds the whole term, and only then walks it to reject functions and ports."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-105274",
        "datePublished": "2026-10-12T16:43:58.730Z",
        "dateReserved": "2026-10-10T13:00:02.355Z",
        "dateUpdated": "2026-10-15T18:05:12.446Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-96618 (GCVE-0-2026-96618)

    Vulnerability from nvd – Published: 2026-10-12 15:29 – Updated: 2026-10-12 15:29
    VLAI
    Title
    Hex exhausts memory and disk on oversized or compressed responses from an untrusted mirror
    Summary
    Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running mix deps.get, mix deps.update, mix hex.package fetch or mix hex.docs fetch. Hex treats a mirror configured with HEX_MIRROR_URL, HEX_MIRROR or mirror_url as untrusted: it doesn't send credentials to it, and it checks registry signatures and package checksums that the mirror can't forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run. Hex.HTTP.request/5 reads the whole response body into memory and decompresses it with :zlib.gunzip/1 whenever the response's Content-Encoding contains gzip, with no limit on the compressed or decompressed size. Hex doesn't ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses. Package tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into deps/<app> in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry. mix hex.docs fetch, and mix hex.docs offline when docs are missing, write the docs tarball to disk and extract it with :mix_hex_erl_tar.extract/2 without the 16 MiB compressed and 128 MiB decompressed limits that mix_hex_tarball:unpack_docs/3 applies. The signed registry doesn't cover docs tarballs, so nothing checks them. Registry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq. This issue affects hex: from 0.11.2 before 2.5.2.
    CWE
    • CWE-409 - Improper Handling of Highly Compressed Data (Data Amplification)
    • CWE-770 - Allocation of Resources Without Limits or Throttling
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.11.2 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 51ea632424fb6ea8765148f96dc25dfeb526b1f8 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP\u0027",
                "\u0027Elixir.Hex.SCM\u0027",
                "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/http.ex",
                "lib/hex/scm.ex",
                "lib/mix/tasks/hex.docs.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP\u0027:request/5"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.11.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP\u0027",
                "\u0027Elixir.Hex.SCM\u0027",
                "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/http.ex",
                "lib/hex/scm.ex",
                "lib/mix/tasks/hex.docs.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP\u0027:request/5"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "bb5189eade682c5fc3f98d9725973a7beb4e1deb",
                      "status": "unaffected"
                    },
                    {
                      "at": "08956100a8283ba500a123e5539ac64d5d7e91d8",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "51ea632424fb6ea8765148f96dc25dfeb526b1f8",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects users who fetch packages or docs through a mirror set with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e, \u003ccode\u003eHEX_MIRROR\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e. Fetches from repo.hex.pm over HTTPS aren\u0027t affected unless TLS verification is broken. A trusted mirror (\u003ccode\u003eHEX_TRUSTED_MIRROR_URL\u003c/code\u003e) or a self-hosted repository can do the same, but Hex already trusts those with credentials.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects users who fetch packages or docs through a mirror set with `HEX_MIRROR_URL`, `HEX_MIRROR` or `mirror_url`. Fetches from repo.hex.pm over HTTPS aren\u0027t affected unless TLS verification is broken. A trusted mirror (`HEX_TRUSTED_MIRROR_URL`) or a self-hosted repository can do the same, but Hex already trusts those with credentials."
                }
              ],
              "value": "Affects users who fetch packages or docs through a mirror set with HEX_MIRROR_URL, HEX_MIRROR or mirror_url. Fetches from repo.hex.pm over HTTPS aren\u0027t affected unless TLS verification is broken. A trusted mirror (HEX_TRUSTED_MIRROR_URL) or a self-hosted repository can do the same, but Hex already trusts those with credentials."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.11.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:00:30.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running \u003ccode\u003emix deps.get\u003c/code\u003e, \u003ccode\u003emix deps.update\u003c/code\u003e, \u003ccode\u003emix hex.package fetch\u003c/code\u003e or \u003ccode\u003emix hex.docs fetch\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eHex treats a mirror configured with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e, \u003ccode\u003eHEX_MIRROR\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e as untrusted: it doesn\u0027t send credentials to it, and it checks registry signatures and package checksums that the mirror can\u0027t forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eHex.HTTP.request/5\u003c/code\u003e reads the whole response body into memory and decompresses it with \u003ccode\u003e:zlib.gunzip/1\u003c/code\u003e whenever the response\u0027s \u003ccode\u003eContent-Encoding\u003c/code\u003e contains \u003ccode\u003egzip\u003c/code\u003e, with no limit on the compressed or decompressed size. Hex doesn\u0027t ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses.\u003c/p\u003e\n\u003cp\u003ePackage tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into \u003ccode\u003edeps/\u0026lt;app\u0026gt;\u003c/code\u003e in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003emix hex.docs fetch\u003c/code\u003e, and \u003ccode\u003emix hex.docs offline\u003c/code\u003e when docs are missing, write the docs tarball to disk and extract it with \u003ccode\u003e:mix_hex_erl_tar.extract/2\u003c/code\u003e without the 16 MiB compressed and 128 MiB decompressed limits that \u003ccode\u003emix_hex_tarball:unpack_docs/3\u003c/code\u003e applies. The signed registry doesn\u0027t cover docs tarballs, so nothing checks them.\u003c/p\u003e\n\u003cp\u003eRegistry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in \u003ca href=\"https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq\" rel=\"noopener noreferrer\"\u003ehttps://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.11.2 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running `mix deps.get`, `mix deps.update`, `mix hex.package fetch` or `mix hex.docs fetch`.\n\nHex treats a mirror configured with `HEX_MIRROR_URL`, `HEX_MIRROR` or `mirror_url` as untrusted: it doesn\u0027t send credentials to it, and it checks registry signatures and package checksums that the mirror can\u0027t forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run.\n\n`Hex.HTTP.request/5` reads the whole response body into memory and decompresses it with `:zlib.gunzip/1` whenever the response\u0027s `Content-Encoding` contains `gzip`, with no limit on the compressed or decompressed size. Hex doesn\u0027t ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses.\n\nPackage tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into `deps/\u003capp\u003e` in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry.\n\n`mix hex.docs fetch`, and `mix hex.docs offline` when docs are missing, write the docs tarball to disk and extract it with `:mix_hex_erl_tar.extract/2` without the 16 MiB compressed and 128 MiB decompressed limits that `mix_hex_tarball:unpack_docs/3` applies. The signed registry doesn\u0027t cover docs tarballs, so nothing checks them.\n\nRegistry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq.\n\nThis issue affects hex: from 0.11.2 before 2.5.2."
                }
              ],
              "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running mix deps.get, mix deps.update, mix hex.package fetch or mix hex.docs fetch.\n\nHex treats a mirror configured with HEX_MIRROR_URL, HEX_MIRROR or mirror_url as untrusted: it doesn\u0027t send credentials to it, and it checks registry signatures and package checksums that the mirror can\u0027t forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run.\n\nHex.HTTP.request/5 reads the whole response body into memory and decompresses it with :zlib.gunzip/1 whenever the response\u0027s Content-Encoding contains gzip, with no limit on the compressed or decompressed size. Hex doesn\u0027t ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses.\n\nPackage tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into deps/\u003capp\u003e in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry.\n\nmix hex.docs fetch, and mix hex.docs offline when docs are missing, write the docs tarball to disk and extract it with :mix_hex_erl_tar.extract/2 without the 16 MiB compressed and 128 MiB decompressed limits that mix_hex_tarball:unpack_docs/3 applies. The signed registry doesn\u0027t cover docs tarballs, so nothing checks them.\n\nRegistry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq.\n\nThis issue affects hex: from 0.11.2 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA mirror operator, or an attacker who controls the mirror\u0027s responses, can make Hex allocate memory or write data far larger than what it sent: in tests against Hex main 851b938, a 65 KB gzip-encoded response decompressed to 64 MiB in memory, a 17 MiB tarball was downloaded in full despite the 16 MiB limit, and a 131 KB docs tarball wrote 129 MiB to disk. Larger responses stop the Erlang VM running Mix or fill the disk, failing builds and CI jobs, and a full disk affects other processes on the machine. No package code has to run, and the mirror doesn\u0027t need the repository\u0027s signing key.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A mirror operator, or an attacker who controls the mirror\u0027s responses, can make Hex allocate memory or write data far larger than what it sent: in tests against Hex main 851b938, a 65 KB gzip-encoded response decompressed to 64 MiB in memory, a 17 MiB tarball was downloaded in full despite the 16 MiB limit, and a 131 KB docs tarball wrote 129 MiB to disk. Larger responses stop the Erlang VM running Mix or fill the disk, failing builds and CI jobs, and a full disk affects other processes on the machine. No package code has to run, and the mirror doesn\u0027t need the repository\u0027s signing key."
                    }
                  ],
                  "value": "A mirror operator, or an attacker who controls the mirror\u0027s responses, can make Hex allocate memory or write data far larger than what it sent: in tests against Hex main 851b938, a 65 KB gzip-encoded response decompressed to 64 MiB in memory, a 17 MiB tarball was downloaded in full despite the 16 MiB limit, and a 131 KB docs tarball wrote 129 MiB to disk. Larger responses stop the Erlang VM running Mix or fill the disk, failing builds and CI jobs, and a full disk affects other processes on the machine. No package code has to run, and the mirror doesn\u0027t need the repository\u0027s signing key."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2.1,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "LOW",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-409",
                  "description": "CWE-409 Improper Handling of Highly Compressed Data (Data Amplification)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            },
            {
              "descriptions": [
                {
                  "cweId": "CWE-770",
                  "description": "CWE-770 Allocation of Resources Without Limits or Throttling",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:29:19.117Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-gf42-pg2f-63jp"
            },
            {
              "name": "EEF CNA record for CVE-2026-96618",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-96618.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-96618",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-96618"
            },
            {
              "name": "Introducing commit 51ea632 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/51ea632424fb6ea8765148f96dc25dfeb526b1f8"
            },
            {
              "name": "Fix commit bb5189e in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/bb5189eade682c5fc3f98d9725973a7beb4e1deb"
            },
            {
              "name": "Fix commit 0895610 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/08956100a8283ba500a123e5539ac64d5d7e91d8"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. Hex then stops downloading a registry file, package, docs tarball or other file from a repository or mirror once it\u0027s larger than 16 MiB, including after decompressing a gzip-encoded response, and checks packages against the registry checksum before writing them to the package cache or unpacking a cached copy.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. Hex then stops downloading a registry file, package, docs tarball or other file from a repository or mirror once it\u0027s larger than 16 MiB, including after decompressing a gzip-encoded response, and checks packages against the registry checksum before writing them to the package cache or unpacking a cached copy."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. Hex then stops downloading a registry file, package, docs tarball or other file from a repository or mirror once it\u0027s larger than 16 MiB, including after decompressing a gzip-encoded response, and checks packages against the registry checksum before writing them to the package cache or unpacking a cached copy."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex exhausts memory and disk on oversized or compressed responses from an untrusted mirror",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eFetch from repo.hex.pm or a mirror you operate. Running Mix under operating system memory and disk limits, such as container limits, confines the effect to that container.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Fetch from repo.hex.pm or a mirror you operate. Running Mix under operating system memory and disk limits, such as container limits, confines the effect to that container."
                }
              ],
              "value": "Fetch from repo.hex.pm or a mirror you operate. Running Mix under operating system memory and disk limits, such as container limits, confines the effect to that container."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eRun a loopback HTTP server that answers with a 65,255-byte gzip stream decompressing to 64 MiB and \u003ccode\u003eContent-Encoding: gzip\u003c/code\u003e. \u003ccode\u003eHex.HTTP.request(:get, url, %{}, nil)\u003c/code\u003e returns a 67,108,864-byte body; peak RSS was 220 MiB, against 91 MiB for an uncompressed control.\u003c/li\u003e\n\u003cli\u003eServe a 17 MiB file as a package tarball. \u003ccode\u003eHex.Repo.get_tarball/3\u003c/code\u003e returns all of it, and only the following unpack fails with \u003ccode\u003e{:tarball, :too_big}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eServe a 131,574-byte docs tarball containing a 129 MiB file and set \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e to the server. \u003ccode\u003emix hex.docs fetch probe 1.0.0\u003c/code\u003e writes the 129 MiB file and reports success.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Run a loopback HTTP server that answers with a 65,255-byte gzip stream decompressing to 64 MiB and `Content-Encoding: gzip`. `Hex.HTTP.request(:get, url, %{}, nil)` returns a 67,108,864-byte body; peak RSS was 220 MiB, against 91 MiB for an uncompressed control.\n2. Serve a 17 MiB file as a package tarball. `Hex.Repo.get_tarball/3` returns all of it, and only the following unpack fails with `{:tarball, :too_big}`.\n3. Serve a 131,574-byte docs tarball containing a 129 MiB file and set `HEX_MIRROR_URL` to the server. `mix hex.docs fetch probe 1.0.0` writes the 129 MiB file and reports success."
                }
              ],
              "value": "* Run a loopback HTTP server that answers with a 65,255-byte gzip stream decompressing to 64 MiB and Content-Encoding: gzip. Hex.HTTP.request(:get, url, %{}, nil) returns a 67,108,864-byte body; peak RSS was 220 MiB, against 91 MiB for an uncompressed control.\n* Serve a 17 MiB file as a package tarball. Hex.Repo.get_tarball/3 returns all of it, and only the following unpack fails with {:tarball, :too_big}.\n* Serve a 131,574-byte docs tarball containing a 129 MiB file and set HEX_MIRROR_URL to the server. mix hex.docs fetch probe 1.0.0 writes the 129 MiB file and reports success."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003eHex.HTTP.request/5\u003c/code\u003e calls \u003ccode\u003e:httpc.request/5\u003c/code\u003e with \u003ccode\u003ebody_format: :binary\u003c/code\u003e, so the whole body is held in memory, and then calls \u003ccode\u003e:zlib.gunzip/1\u003c/code\u003e when the \u003ccode\u003econtent-encoding\u003c/code\u003e header contains \u003ccode\u003egzip\u003c/code\u003e. Hex doesn\u0027t send \u003ccode\u003eAccept-Encoding\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eWhen \u003ccode\u003emirror_url\u003c/code\u003e is set, \u003ccode\u003eHex.Repo\u003c/code\u003e sends registry, tarball and docs requests to the mirror and marks it untrusted, so no credentials are sent to it.\u003c/li\u003e\n\u003cli\u003eHex 2.5.1: \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e writes the body returned by \u003ccode\u003eHex.Repo.get_tarball/3\u003c/code\u003e to the cache. \u003ccode\u003eHex.SCM.update/1\u003c/code\u003e deletes \u003ccode\u003edeps/\u0026lt;app\u0026gt;\u003c/code\u003e, unpacks the tarball into it with \u003ccode\u003eHex.Tar.unpack!/2\u003c/code\u003e and compares the inner and outer checksums afterwards. Development branch: \u003ccode\u003eHex.Repo.get_tarball_to_file/4\u003c/code\u003e streams the tarball to a temporary file without counting bytes; the file is renamed into the cache and unpacked into a staging directory before the checksums are compared.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eMix.Tasks.Hex.Docs\u003c/code\u003e writes the body returned by \u003ccode\u003eHex.Repo.get_docs/3\u003c/code\u003e to disk and calls \u003ccode\u003e:mix_hex_erl_tar.extract/2\u003c/code\u003e with \u003ccode\u003e[:compressed, cwd: ...]\u003c/code\u003e and no \u003ccode\u003emax_size\u003c/code\u003e, while \u003ccode\u003emix_hex_tarball:unpack_docs/3\u003c/code\u003e enforces a 16 MiB compressed and 128 MiB decompressed limit.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `Hex.HTTP.request/5` calls `:httpc.request/5` with `body_format: :binary`, so the whole body is held in memory, and then calls `:zlib.gunzip/1` when the `content-encoding` header contains `gzip`. Hex doesn\u0027t send `Accept-Encoding`.\n2. When `mirror_url` is set, `Hex.Repo` sends registry, tarball and docs requests to the mirror and marks it untrusted, so no credentials are sent to it.\n3. Hex 2.5.1: `Hex.SCM.fetch/3` writes the body returned by `Hex.Repo.get_tarball/3` to the cache. `Hex.SCM.update/1` deletes `deps/\u003capp\u003e`, unpacks the tarball into it with `Hex.Tar.unpack!/2` and compares the inner and outer checksums afterwards. Development branch: `Hex.Repo.get_tarball_to_file/4` streams the tarball to a temporary file without counting bytes; the file is renamed into the cache and unpacked into a staging directory before the checksums are compared.\n4. `Mix.Tasks.Hex.Docs` writes the body returned by `Hex.Repo.get_docs/3` to disk and calls `:mix_hex_erl_tar.extract/2` with `[:compressed, cwd: ...]` and no `max_size`, while `mix_hex_tarball:unpack_docs/3` enforces a 16 MiB compressed and 128 MiB decompressed limit."
                }
              ],
              "value": "* Hex.HTTP.request/5 calls :httpc.request/5 with body_format: :binary, so the whole body is held in memory, and then calls :zlib.gunzip/1 when the content-encoding header contains gzip. Hex doesn\u0027t send Accept-Encoding.\n* When mirror_url is set, Hex.Repo sends registry, tarball and docs requests to the mirror and marks it untrusted, so no credentials are sent to it.\n* Hex 2.5.1: Hex.SCM.fetch/3 writes the body returned by Hex.Repo.get_tarball/3 to the cache. Hex.SCM.update/1 deletes deps/\u003capp\u003e, unpacks the tarball into it with Hex.Tar.unpack!/2 and compares the inner and outer checksums afterwards. Development branch: Hex.Repo.get_tarball_to_file/4 streams the tarball to a temporary file without counting bytes; the file is renamed into the cache and unpacked into a staging directory before the checksums are compared.\n* Mix.Tasks.Hex.Docs writes the body returned by Hex.Repo.get_docs/3 to disk and calls :mix_hex_erl_tar.extract/2 with [:compressed, cwd: ...] and no max_size, while mix_hex_tarball:unpack_docs/3 enforces a 16 MiB compressed and 128 MiB decompressed limit."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-96618",
        "datePublished": "2026-10-12T15:29:19.117Z",
        "dateReserved": "2026-10-10T13:00:02.352Z",
        "dateUpdated": "2026-10-12T15:29:19.117Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-96612 (GCVE-0-2026-96612)

    Vulnerability from nvd – Published: 2026-10-12 15:39 – Updated: 2026-10-12 15:39
    VLAI
    Title
    Path traversal in Hex via unvalidated dependency app names
    Summary
    Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project's deps directory and extract package files into it when a developer fetches dependencies. A package release's requirements carry an app label that names the dependency's OTP application. Hex takes this label from the repository's signed registry and uses it as the dependency's application name without validating it (Hex.RemoteConverger.deps/2, Hex.Mix.to_lock/1). Mix derives the dependency's checkout directory as deps/<app>, and Hex.SCM.update/1 runs File.rm_rf!/1 on that directory and unpacks the package into it. hex.pm only checks the label's length, so a publisher can set it to a value such as ../../target. When a project depends on such a release directly or transitively, mix deps.get or mix deps.update deletes the directory the label resolves to and writes the labelled package's files there. This happens before any dependency code is compiled. This issue affects hex: from 0.6.0 before 2.5.2.
    CWE
    • CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.6.0 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 380f87054e1bc08ee13d2b5311bc01f98dad2fc6 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Mix\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/mix.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:deps/2"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:converge/2"
                },
                {
                  "name": "\u0027Elixir.Hex.Mix\u0027:to_lock/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:checkout/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.6.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Mix\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/mix.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:deps/2"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:converge/2"
                },
                {
                  "name": "\u0027Elixir.Hex.Mix\u0027:to_lock/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:checkout/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "1b3e2ae8f0dd7273a2c2625b9e50b6c67c8568fb",
                      "status": "unaffected"
                    },
                    {
                      "at": "72279a8e2004b32b20d8767ff010c117193dd02c",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "380f87054e1bc08ee13d2b5311bc01f98dad2fc6",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects projects whose dependency tree, directly or transitively, contains a package release whose registry metadata carries a crafted dependency \u003ccode\u003eapp\u003c/code\u003e label, when dependencies are fetched with \u003ccode\u003emix deps.get\u003c/code\u003e or \u003ccode\u003emix deps.update\u003c/code\u003e. Packages on hex.pm are affected while hex.pm accepts such labels; packages on self-hosted repositories are affected when the repository operator signs such metadata.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects projects whose dependency tree, directly or transitively, contains a package release whose registry metadata carries a crafted dependency `app` label, when dependencies are fetched with `mix deps.get` or `mix deps.update`. Packages on hex.pm are affected while hex.pm accepts such labels; packages on self-hosted repositories are affected when the repository operator signs such metadata."
                }
              ],
              "value": "Affects projects whose dependency tree, directly or transitively, contains a package release whose registry metadata carries a crafted dependency app label, when dependencies are fetched with mix deps.get or mix deps.update. Packages on hex.pm are affected while hex.pm accepts such labels; packages on self-hosted repositories are affected when the repository operator signs such metadata."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.6.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-07T22:03:18.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027) vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project\u0027s \u003ccode\u003edeps\u003c/code\u003e directory and extract package files into it when a developer fetches dependencies.\u003c/p\u003e\n\u003cp\u003eA package release\u0027s requirements carry an \u003ccode\u003eapp\u003c/code\u003e label that names the dependency\u0027s OTP application. Hex takes this label from the repository\u0027s signed registry and uses it as the dependency\u0027s application name without validating it (\u003ccode\u003eHex.RemoteConverger.deps/2\u003c/code\u003e, \u003ccode\u003eHex.Mix.to_lock/1\u003c/code\u003e). Mix derives the dependency\u0027s checkout directory as \u003ccode\u003edeps/\u0026lt;app\u0026gt;\u003c/code\u003e, and \u003ccode\u003eHex.SCM.update/1\u003c/code\u003e runs \u003ccode\u003eFile.rm_rf!/1\u003c/code\u003e on that directory and unpacks the package into it. hex.pm only checks the label\u0027s length, so a publisher can set it to a value such as \u003ccode\u003e../../target\u003c/code\u003e. When a project depends on such a release directly or transitively, \u003ccode\u003emix deps.get\u003c/code\u003e or \u003ccode\u003emix deps.update\u003c/code\u003e deletes the directory the label resolves to and writes the labelled package\u0027s files there. This happens before any dependency code is compiled.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.6.0 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027) vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project\u0027s `deps` directory and extract package files into it when a developer fetches dependencies.\n\nA package release\u0027s requirements carry an `app` label that names the dependency\u0027s OTP application. Hex takes this label from the repository\u0027s signed registry and uses it as the dependency\u0027s application name without validating it (`Hex.RemoteConverger.deps/2`, `Hex.Mix.to_lock/1`). Mix derives the dependency\u0027s checkout directory as `deps/\u003capp\u003e`, and `Hex.SCM.update/1` runs `File.rm_rf!/1` on that directory and unpacks the package into it. hex.pm only checks the label\u0027s length, so a publisher can set it to a value such as `../../target`. When a project depends on such a release directly or transitively, `mix deps.get` or `mix deps.update` deletes the directory the label resolves to and writes the labelled package\u0027s files there. This happens before any dependency code is compiled.\n\nThis issue affects hex: from 0.6.0 before 2.5.2."
                }
              ],
              "value": "Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027) vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project\u0027s deps directory and extract package files into it when a developer fetches dependencies.\n\nA package release\u0027s requirements carry an app label that names the dependency\u0027s OTP application. Hex takes this label from the repository\u0027s signed registry and uses it as the dependency\u0027s application name without validating it (Hex.RemoteConverger.deps/2, Hex.Mix.to_lock/1). Mix derives the dependency\u0027s checkout directory as deps/\u003capp\u003e, and Hex.SCM.update/1 runs File.rm_rf!/1 on that directory and unpacks the package into it. hex.pm only checks the label\u0027s length, so a publisher can set it to a value such as ../../target. When a project depends on such a release directly or transitively, mix deps.get or mix deps.update deletes the directory the label resolves to and writes the labelled package\u0027s files there. This happens before any dependency code is compiled.\n\nThis issue affects hex: from 0.6.0 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-126",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA publisher of any package in a project\u0027s dependency tree can make \u003ccode\u003emix deps.get\u003c/code\u003e delete a directory that the developer\u0027s account can write and that \u003ccode\u003e..\u003c/code\u003e segments relative to \u003ccode\u003edeps\u003c/code\u003e reach, such as the project directory or its parent, and fill it with the labelled package\u0027s files. Writing attacker-chosen files into a directory whose contents are later run or loaded can lead to code execution without the developer compiling the dependency. Developers who fetch dependencies to review them before compiling, CI jobs and dependency update bots that only run \u003ccode\u003emix deps.get\u003c/code\u003e or \u003ccode\u003emix deps.update\u003c/code\u003e are affected.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A publisher of any package in a project\u0027s dependency tree can make `mix deps.get` delete a directory that the developer\u0027s account can write and that `..` segments relative to `deps` reach, such as the project directory or its parent, and fill it with the labelled package\u0027s files. Writing attacker-chosen files into a directory whose contents are later run or loaded can lead to code execution without the developer compiling the dependency. Developers who fetch dependencies to review them before compiling, CI jobs and dependency update bots that only run `mix deps.get` or `mix deps.update` are affected."
                    }
                  ],
                  "value": "A publisher of any package in a project\u0027s dependency tree can make mix deps.get delete a directory that the developer\u0027s account can write and that .. segments relative to deps reach, such as the project directory or its parent, and fill it with the labelled package\u0027s files. Writing attacker-chosen files into a directory whose contents are later run or loaded can lead to code execution without the developer compiling the dependency. Developers who fetch dependencies to review them before compiling, CI jobs and dependency update bots that only run mix deps.get or mix deps.update are affected."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 7.5,
                "baseSeverity": "HIGH",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-22",
                  "description": "CWE-22 Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:39:49.862Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-2vjj-c5hr-6xc3"
            },
            {
              "name": "EEF CNA record for CVE-2026-96612",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-96612.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-96612",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-96612"
            },
            {
              "name": "Introducing commit 380f870 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/380f87054e1bc08ee13d2b5311bc01f98dad2fc6"
            },
            {
              "name": "Fix commit 1b3e2ae in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/1b3e2ae8f0dd7273a2c2625b9e50b6c67c8568fb"
            },
            {
              "name": "Fix commit 72279a8 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/72279a8e2004b32b20d8767ff010c117193dd02c"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. Hex then skips package releases that give a dependency an application name other than a letter followed by letters, digits, \u003ccode\u003e_\u003c/code\u003e and \u003ccode\u003e-\u003c/code\u003e, and warns about them. Resolution fails if no other release of the package fits the requirements.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. Hex then skips package releases that give a dependency an application name other than a letter followed by letters, digits, `_` and `-`, and warns about them. Resolution fails if no other release of the package fits the requirements."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. Hex then skips package releases that give a dependency an application name other than a letter followed by letters, digits, _ and -, and warns about them. Resolution fails if no other release of the package fits the requirements."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Path traversal in Hex via unvalidated dependency app names",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eBefore running \u003ccode\u003emix deps.get\u003c/code\u003e on a \u003ccode\u003emix.lock\u003c/code\u003e from an untrusted change, check that every key in \u003ccode\u003emix.lock\u003c/code\u003e is a plain application name without \u003ccode\u003e/\u003c/code\u003e, \u003ccode\u003e\\\u003c/code\u003e or \u003ccode\u003e..\u003c/code\u003e. There\u0027s no workaround for new dependency resolution with \u003ccode\u003emix deps.update\u003c/code\u003e or \u003ccode\u003emix deps.get\u003c/code\u003e without a lock entry.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Before running `mix deps.get` on a `mix.lock` from an untrusted change, check that every key in `mix.lock` is a plain application name without `/`, `\\` or `..`. There\u0027s no workaround for new dependency resolution with `mix deps.update` or `mix deps.get` without a lock entry."
                }
              ],
              "value": "Before running mix deps.get on a mix.lock from an untrusted change, check that every key in mix.lock is a plain application name without /, \\ or ... There\u0027s no workaround for new dependency resolution with mix deps.update or mix deps.get without a lock entry."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003ePublish package \u003ccode\u003ebeta\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003ePublish package \u003ccode\u003ealpha\u003c/code\u003e with a requirement on \u003ccode\u003ebeta\u003c/code\u003e whose \u003ccode\u003eapp\u003c/code\u003e is \u003ccode\u003e../../escape_marker\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eIn a project that depends on \u003ccode\u003ealpha\u003c/code\u003e, create \u003ccode\u003e../escape_marker/canary.txt\u003c/code\u003e next to the project directory.\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003emix deps.get\u003c/code\u003e. Hex prints \u003ccode\u003e* Updating ../../escape_marker (Hex package)\u003c/code\u003e, deletes \u003ccode\u003ecanary.txt\u003c/code\u003e and writes \u003ccode\u003ebeta\u003c/code\u003e\u0027s files into \u003ccode\u003e../escape_marker\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Publish package `beta`.\n2. Publish package `alpha` with a requirement on `beta` whose `app` is `../../escape_marker`.\n3. In a project that depends on `alpha`, create `../escape_marker/canary.txt` next to the project directory.\n4. Run `mix deps.get`. Hex prints `* Updating ../../escape_marker (Hex package)`, deletes `canary.txt` and writes `beta`\u0027s files into `../escape_marker`."
                }
              ],
              "value": "* Publish package beta.\n* Publish package alpha with a requirement on beta whose app is ../../escape_marker.\n* In a project that depends on alpha, create ../escape_marker/canary.txt next to the project directory.\n* Run mix deps.get. Hex prints * Updating ../../escape_marker (Hex package), deletes canary.txt and writes beta\u0027s files into ../escape_marker."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003ehex.pm stores each requirement\u0027s \u003ccode\u003eapp\u003c/code\u003e field with only a length check (255 codepoints) and copies it into the signed package registry resource when it differs from the dependency\u0027s package name.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.RemoteConverger.deps/2\u003c/code\u003e returns the dependency\u0027s children with \u003ccode\u003eString.to_atom/1\u003c/code\u003e of that label as the application name, and \u003ccode\u003eHex.Mix.to_lock/1\u003c/code\u003e writes it as the \u003ccode\u003emix.lock\u003c/code\u003e key.\u003c/li\u003e\n\u003cli\u003eMix computes the dependency destination as \u003ccode\u003ePath.join(Mix.Project.deps_path(), Atom.to_string(app))\u003c/code\u003e without validating the name.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.SCM.update/1\u003c/code\u003e calls \u003ccode\u003eFile.rm_rf!(dest)\u003c/code\u003e and then \u003ccode\u003eHex.Tar.unpack!(path, dest)\u003c/code\u003e, so a label containing \u003ccode\u003e..\u003c/code\u003e segments deletes and repopulates a directory outside \u003ccode\u003edeps\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eMix doesn\u0027t evaluate a Hex dependency\u0027s \u003ccode\u003emix.exs\u003c/code\u003e during \u003ccode\u003emix deps.get\u003c/code\u003e, so this is reachable before any package code runs.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. hex.pm stores each requirement\u0027s `app` field with only a length check (255 codepoints) and copies it into the signed package registry resource when it differs from the dependency\u0027s package name.\n2. `Hex.RemoteConverger.deps/2` returns the dependency\u0027s children with `String.to_atom/1` of that label as the application name, and `Hex.Mix.to_lock/1` writes it as the `mix.lock` key.\n3. Mix computes the dependency destination as `Path.join(Mix.Project.deps_path(), Atom.to_string(app))` without validating the name.\n4. `Hex.SCM.update/1` calls `File.rm_rf!(dest)` and then `Hex.Tar.unpack!(path, dest)`, so a label containing `..` segments deletes and repopulates a directory outside `deps`.\n5. Mix doesn\u0027t evaluate a Hex dependency\u0027s `mix.exs` during `mix deps.get`, so this is reachable before any package code runs."
                }
              ],
              "value": "* hex.pm stores each requirement\u0027s app field with only a length check (255 codepoints) and copies it into the signed package registry resource when it differs from the dependency\u0027s package name.\n* Hex.RemoteConverger.deps/2 returns the dependency\u0027s children with String.to_atom/1 of that label as the application name, and Hex.Mix.to_lock/1 writes it as the mix.lock key.\n* Mix computes the dependency destination as Path.join(Mix.Project.deps_path(), Atom.to_string(app)) without validating the name.\n* Hex.SCM.update/1 calls File.rm_rf!(dest) and then Hex.Tar.unpack!(path, dest), so a label containing .. segments deletes and repopulates a directory outside deps.\n* Mix doesn\u0027t evaluate a Hex dependency\u0027s mix.exs during mix deps.get, so this is reachable before any package code runs."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-96612",
        "datePublished": "2026-10-12T15:39:49.862Z",
        "dateReserved": "2026-10-01T09:00:02.103Z",
        "dateUpdated": "2026-10-12T15:39:49.862Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-81856 (GCVE-0-2026-81856)

    Vulnerability from nvd – Published: 2026-10-12 15:46 – Updated: 2026-10-12 15:46
    VLAI
    Title
    Terminal escape sequence injection in Hex via unneutralized server-supplied output
    Summary
    Improper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks. Hex prints strings supplied by the package repository and the documentation search service straight to the terminal through Hex.Shell.info/1 and Hex.Shell.error/1, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in mix hex.info, search results in mix hex.package search and mix hex.search, owner and organization listings, publish and sponsor URLs, the authenticated username in mix hex.user, policy identities in mix hex.policy, and API error bodies rendered by Hex.Utils.print_error_result/1. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package. This issue affects hex: from 0.0.1 before 2.5.2.
    CWE
    • CWE-150 - Improper Neutralization of Escape, Meta, or Control Sequences
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.0.1 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 211303e3f68f5d3ce06450c1ff1a7a770a9ab236 , < dd3305ddf0032f6d0b468fd40dbbc3072bfcb8b8 (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Search\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.search.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Search\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.0.1",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Search\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.search.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Search\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "dd3305ddf0032f6d0b468fd40dbbc3072bfcb8b8",
                  "status": "affected",
                  "version": "211303e3f68f5d3ce06450c1ff1a7a770a9ab236",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eReachable only when a developer runs an affected Mix task in a terminal emulator that interprets ANSI escape sequences, and the printed content originates from an attacker-published package or a hostile repository server.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Reachable only when a developer runs an affected Mix task in a terminal emulator that interprets ANSI escape sequences, and the printed content originates from an attacker-published package or a hostile repository server."
                }
              ],
              "value": "Reachable only when a developer runs an affected Mix task in a terminal emulator that interprets ANSI escape sequences, and the printed content originates from an attacker-published package or a hostile repository server."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.0.1",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "reporter",
              "value": "Zach Daniel"
            },
            {
              "lang": "en",
              "type": "remediation reviewer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Jonatan M\u00e4nnchen"
            },
            {
              "lang": "en",
              "type": "coordinator",
              "value": "Jonatan M\u00e4nnchen"
            }
          ],
          "dateAssigned": "2026-09-09T16:47:17.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks.\u003c/p\u003e\n\u003cp\u003eHex prints strings supplied by the package repository and the documentation search service straight to the terminal through \u003ccode\u003eHex.Shell.info/1\u003c/code\u003e and \u003ccode\u003eHex.Shell.error/1\u003c/code\u003e, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in \u003ccode\u003emix hex.info\u003c/code\u003e, search results in \u003ccode\u003emix hex.package search\u003c/code\u003e and \u003ccode\u003emix hex.search\u003c/code\u003e, owner and organization listings, publish and sponsor URLs, the authenticated username in \u003ccode\u003emix hex.user\u003c/code\u003e, policy identities in \u003ccode\u003emix hex.policy\u003c/code\u003e, and API error bodies rendered by \u003ccode\u003eHex.Utils.print_error_result/1\u003c/code\u003e. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.0.1 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks.\n\nHex prints strings supplied by the package repository and the documentation search service straight to the terminal through `Hex.Shell.info/1` and `Hex.Shell.error/1`, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in `mix hex.info`, search results in `mix hex.package search` and `mix hex.search`, owner and organization listings, publish and sponsor URLs, the authenticated username in `mix hex.user`, policy identities in `mix hex.policy`, and API error bodies rendered by `Hex.Utils.print_error_result/1`. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package.\n\nThis issue affects hex: from 0.0.1 before 2.5.2."
                }
              ],
              "value": "Improper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks.\n\nHex prints strings supplied by the package repository and the documentation search service straight to the terminal through Hex.Shell.info/1 and Hex.Shell.error/1, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in mix hex.info, search results in mix hex.package search and mix hex.search, owner and organization listings, publish and sponsor URLs, the authenticated username in mix hex.user, policy identities in mix hex.policy, and API error bodies rendered by Hex.Utils.print_error_result/1. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package.\n\nThis issue affects hex: from 0.0.1 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-93",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA malicious package publisher can forge what a developer sees when running \u003ccode\u003emix hex.search\u003c/code\u003e, rewriting the displayed hexdocs URL or a suggested command, concealing real output, or writing attacker-chosen text to the clipboard through OSC 52. Any developer who runs a documentation search that surfaces the attacker\u0027s package is affected.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A malicious package publisher can forge what a developer sees when running `mix hex.search`, rewriting the displayed hexdocs URL or a suggested command, concealing real output, or writing attacker-chosen text to the clipboard through OSC 52. Any developer who runs a documentation search that surfaces the attacker\u0027s package is affected."
                    }
                  ],
                  "value": "A malicious package publisher can forge what a developer sees when running mix hex.search, rewriting the displayed hexdocs URL or a suggested command, concealing real output, or writing attacker-chosen text to the clipboard through OSC 52. Any developer who runs a documentation search that surfaces the attacker\u0027s package is affected."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2.3,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "PASSIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "LOW",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-150",
                  "description": "CWE-150 Improper Neutralization of Escape, Meta, or Control Sequences",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:46:12.146Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-fpmj-3cxg-p766"
            },
            {
              "name": "EEF CNA record for CVE-2026-81856",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-81856.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-81856",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-81856"
            },
            {
              "name": "Introducing commit 211303e in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/211303e3f68f5d3ce06450c1ff1a7a770a9ab236"
            },
            {
              "name": "Fix commit dd3305d in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/dd3305ddf0032f6d0b468fd40dbbc3072bfcb8b8"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. Hex then escapes terminal control characters in text from hex.pm and the registry before printing it, and rejects registry dependencies whose package or repository name isn\u0027t a valid name.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. Hex then escapes terminal control characters in text from hex.pm and the registry before printing it, and rejects registry dependencies whose package or repository name isn\u0027t a valid name."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. Hex then escapes terminal control characters in text from hex.pm and the registry before printing it, and rejects registry dependencies whose package or repository name isn\u0027t a valid name."
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "Terminal escape sequence injection in Hex via unneutralized server-supplied output"
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-81856",
        "datePublished": "2026-10-12T15:46:12.146Z",
        "dateReserved": "2026-08-31T00:45:02.431Z",
        "dateUpdated": "2026-10-12T15:46:12.146Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-105668 (GCVE-0-2026-105668)

    Vulnerability from nvd – Published: 2026-10-12 15:31 – Updated: 2026-10-12 15:31
    VLAI
    Title
    Hex release-age cooldown is lifted package-wide when the locked release is retired
    Summary
    Protection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner's account, to get a newly published release past the release-age cooldown. The cooldown (cooldown config, HEX_COOLDOWN) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in mix.lock is retired or has a security advisory, Hex.RemoteConverger.build_cooldown_bypass/3 and Hex.RemoteConverger.unsafe_lock_bypass/1 lift the cooldown for every version of that package and of every package the locked release depends on, so that mix deps.update can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next mix deps.update that unlocks the package selects the new release regardless of its age. Hex.Registry.Cooldown.versions/2 checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected. This issue affects hex: from 2.5.0 before 2.5.2.
    CWE
    • CWE-693 - Protection Mechanism Failure
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 2.5.0 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: b4e665d46be8a5f81e8cbbe4c3a67058a19cf133 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Registry.Cooldown\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/registry/cooldown.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:build_cooldown_bypass/3"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:unsafe_lock_bypass/1"
                },
                {
                  "name": "\u0027Elixir.Hex.Registry.Cooldown\u0027:versions/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "2.5.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Registry.Cooldown\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/registry/cooldown.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:build_cooldown_bypass/3"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:unsafe_lock_bypass/1"
                },
                {
                  "name": "\u0027Elixir.Hex.Registry.Cooldown\u0027:versions/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "eed2bdf85320ae9e244629511c03f5f3f8c5d0b5",
                      "status": "unaffected"
                    },
                    {
                      "at": "1b6fddfeadd98ed26a143f60356efade0494e2ae",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "b4e665d46be8a5f81e8cbbe4c3a67058a19cf133",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects projects that set the \u003ccode\u003ecooldown\u003c/code\u003e config or \u003ccode\u003eHEX_COOLDOWN\u003c/code\u003e and update dependencies with \u003ccode\u003emix deps.update\u003c/code\u003e, or otherwise unlock the package during resolution. Cooldowns enforced through an organization dependency policy aren\u0027t affected.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects projects that set the `cooldown` config or `HEX_COOLDOWN` and update dependencies with `mix deps.update`, or otherwise unlock the package during resolution. Cooldowns enforced through an organization dependency policy aren\u0027t affected."
                }
              ],
              "value": "Affects projects that set the cooldown config or HEX_COOLDOWN and update dependencies with mix deps.update, or otherwise unlock the package during resolution. Cooldowns enforced through an organization dependency policy aren\u0027t affected."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "2.5.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "coordinator",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:01:56.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eProtection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner\u0027s account, to get a newly published release past the release-age cooldown.\u003c/p\u003e\n\u003cp\u003eThe cooldown (\u003ccode\u003ecooldown\u003c/code\u003e config, \u003ccode\u003eHEX_COOLDOWN\u003c/code\u003e) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in \u003ccode\u003emix.lock\u003c/code\u003e is retired or has a security advisory, \u003ccode\u003eHex.RemoteConverger.build_cooldown_bypass/3\u003c/code\u003e and \u003ccode\u003eHex.RemoteConverger.unsafe_lock_bypass/1\u003c/code\u003e lift the cooldown for every version of that package and of every package the locked release depends on, so that \u003ccode\u003emix deps.update\u003c/code\u003e can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next \u003ccode\u003emix deps.update\u003c/code\u003e that unlocks the package selects the new release regardless of its age. \u003ccode\u003eHex.Registry.Cooldown.versions/2\u003c/code\u003e checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 2.5.0 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Protection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner\u0027s account, to get a newly published release past the release-age cooldown.\n\nThe cooldown (`cooldown` config, `HEX_COOLDOWN`) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in `mix.lock` is retired or has a security advisory, `Hex.RemoteConverger.build_cooldown_bypass/3` and `Hex.RemoteConverger.unsafe_lock_bypass/1` lift the cooldown for every version of that package and of every package the locked release depends on, so that `mix deps.update` can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next `mix deps.update` that unlocks the package selects the new release regardless of its age. `Hex.Registry.Cooldown.versions/2` checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected.\n\nThis issue affects hex: from 2.5.0 before 2.5.2."
                }
              ],
              "value": "Protection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner\u0027s account, to get a newly published release past the release-age cooldown.\n\nThe cooldown (cooldown config, HEX_COOLDOWN) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in mix.lock is retired or has a security advisory, Hex.RemoteConverger.build_cooldown_bypass/3 and Hex.RemoteConverger.unsafe_lock_bypass/1 lift the cooldown for every version of that package and of every package the locked release depends on, so that mix deps.update can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next mix deps.update that unlocks the package selects the new release regardless of its age. Hex.Registry.Cooldown.versions/2 checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected.\n\nThis issue affects hex: from 2.5.0 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-538",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eThe cooldown exists to keep a compromised release out of projects until it can be detected and retired. An attacker who controls a package owner account can defeat it by also retiring the currently locked release, so a malicious release reaches projects that rely on the local cooldown as soon as they run \u003ccode\u003emix deps.update\u003c/code\u003e, including automated dependency update jobs. The malicious release\u0027s code then runs when the dependency is compiled.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "The cooldown exists to keep a compromised release out of projects until it can be detected and retired. An attacker who controls a package owner account can defeat it by also retiring the currently locked release, so a malicious release reaches projects that rely on the local cooldown as soon as they run `mix deps.update`, including automated dependency update jobs. The malicious release\u0027s code then runs when the dependency is compiled."
                    }
                  ],
                  "value": "The cooldown exists to keep a compromised release out of projects until it can be detected and retired. An attacker who controls a package owner account can defeat it by also retiring the currently locked release, so a malicious release reaches projects that rely on the local cooldown as soon as they run mix deps.update, including automated dependency update jobs. The malicious release\u0027s code then runs when the dependency is compiled."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 7.1,
                "baseSeverity": "HIGH",
                "privilegesRequired": "HIGH",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-693",
                  "description": "CWE-693 Protection Mechanism Failure",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:31:58.926Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-pqhp-5x9x-69h7"
            },
            {
              "name": "EEF CNA record for CVE-2026-105668",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-105668.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-105668",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-105668"
            },
            {
              "name": "Introducing commit b4e665d in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/b4e665d46be8a5f81e8cbbe4c3a67058a19cf133"
            },
            {
              "name": "Fix commit eed2bdf in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/eed2bdf85320ae9e244629511c03f5f3f8c5d0b5"
            },
            {
              "name": "Fix commit 1b6fddf in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/1b6fddfeadd98ed26a143f60356efade0494e2ae"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. A retired locked release then no longer lifts the release-age cooldown for its package. A locked release with a security advisory still lifts it for its package and the direct dependencies of the locked release, only in the repository the package is locked from.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. A retired locked release then no longer lifts the release-age cooldown for its package. A locked release with a security advisory still lifts it for its package and the direct dependencies of the locked release, only in the repository the package is locked from."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. A retired locked release then no longer lifts the release-age cooldown for its package. A locked release with a security advisory still lifts it for its package and the direct dependencies of the locked release, only in the repository the package is locked from."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex release-age cooldown is lifted package-wide when the locked release is retired",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eEnforce the cooldown through an organization dependency policy instead of the local \u003ccode\u003ecooldown\u003c/code\u003e setting, or run \u003ccode\u003emix hex.audit\u003c/code\u003e before \u003ccode\u003emix deps.update\u003c/code\u003e and don\u0027t update a package whose locked release was retired until its replacement has been reviewed.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Enforce the cooldown through an organization dependency policy instead of the local `cooldown` setting, or run `mix hex.audit` before `mix deps.update` and don\u0027t update a package whose locked release was retired until its replacement has been reviewed."
                }
              ],
              "value": "Enforce the cooldown through an organization dependency policy instead of the local cooldown setting, or run mix hex.audit before mix deps.update and don\u0027t update a package whose locked release was retired until its replacement has been reviewed."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eLock \u003ccode\u003efoo 1.0.0\u003c/code\u003e in a project with \u003ccode\u003eHEX_COOLDOWN=7d\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003ePublish \u003ccode\u003efoo 1.0.1\u003c/code\u003e; \u003ccode\u003emix deps.update foo\u003c/code\u003e reports it as filtered by cooldown and keeps 1.0.0.\u003c/li\u003e\n\u003cli\u003eRetire \u003ccode\u003efoo 1.0.0\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003emix deps.update foo\u003c/code\u003e again; it upgrades to the 1-hour-old 1.0.1.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Lock `foo 1.0.0` in a project with `HEX_COOLDOWN=7d`.\n2. Publish `foo 1.0.1`; `mix deps.update foo` reports it as filtered by cooldown and keeps 1.0.0.\n3. Retire `foo 1.0.0`.\n4. Run `mix deps.update foo` again; it upgrades to the 1-hour-old 1.0.1."
                }
              ],
              "value": "* Lock foo 1.0.0 in a project with HEX_COOLDOWN=7d.\n* Publish foo 1.0.1; mix deps.update foo reports it as filtered by cooldown and keeps 1.0.0.\n* Retire foo 1.0.0.\n* Run mix deps.update foo again; it upgrades to the 1-hour-old 1.0.1."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003eHex.RemoteConverger.build_cooldown_bypass/3\u003c/code\u003e adds \u003ccode\u003eunsafe_lock_bypass(old_lock)\u003c/code\u003e to the set of packages exempt from the cooldown.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eunsafe_lock_bypass/1\u003c/code\u003e adds a package\u0027s name, and the names of its locked children, whenever \u003ccode\u003eRegistry.retired/3\u003c/code\u003e or \u003ccode\u003eRegistry.advisories/3\u003c/code\u003e reports the locked version as unsafe.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.Registry.Cooldown.versions/2\u003c/code\u003e returns every version unfiltered for any package name in that set, so freshly published versions become eligible as soon as the package is unlocked.\u003c/li\u003e\n\u003cli\u003ehex.pm lets the package owner retire any of their releases, so the owner controls the trigger. \u003ccode\u003eHex.Policy.Filter\u003c/code\u003e applies policy cooldowns without consulting the bypass set.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `Hex.RemoteConverger.build_cooldown_bypass/3` adds `unsafe_lock_bypass(old_lock)` to the set of packages exempt from the cooldown.\n2. `unsafe_lock_bypass/1` adds a package\u0027s name, and the names of its locked children, whenever `Registry.retired/3` or `Registry.advisories/3` reports the locked version as unsafe.\n3. `Hex.Registry.Cooldown.versions/2` returns every version unfiltered for any package name in that set, so freshly published versions become eligible as soon as the package is unlocked.\n4. hex.pm lets the package owner retire any of their releases, so the owner controls the trigger. `Hex.Policy.Filter` applies policy cooldowns without consulting the bypass set."
                }
              ],
              "value": "* Hex.RemoteConverger.build_cooldown_bypass/3 adds unsafe_lock_bypass(old_lock) to the set of packages exempt from the cooldown.\n* unsafe_lock_bypass/1 adds a package\u0027s name, and the names of its locked children, whenever Registry.retired/3 or Registry.advisories/3 reports the locked version as unsafe.\n* Hex.Registry.Cooldown.versions/2 returns every version unfiltered for any package name in that set, so freshly published versions become eligible as soon as the package is unlocked.\n* hex.pm lets the package owner retire any of their releases, so the owner controls the trigger. Hex.Policy.Filter applies policy cooldowns without consulting the bypass set."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-105668",
        "datePublished": "2026-10-12T15:31:58.926Z",
        "dateReserved": "2026-10-07T22:15:01.885Z",
        "dateUpdated": "2026-10-12T15:31:58.926Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-105280 (GCVE-0-2026-105280)

    Vulnerability from nvd – Published: 2026-10-12 15:30 – Updated: 2026-10-12 15:30
    VLAI
    Title
    Hex writes unverified package tarballs to standard output in mix hex.package fetch
    Summary
    Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that mix hex.package fetch PACKAGE VERSION --output - writes to standard output. Hex compares a fetched tarball's inner and outer checksums with the repository's signed registry before writing it to a file or unpacking it. The standard output branch of mix hex.package fetch writes the bytes returned by Hex.SCM.fetch/3 without that comparison, and Hex.SCM.fetch/3 doesn't verify freshly downloaded tarballs itself. When a mirror configured with HEX_MIRROR_URL or mirror_url serves altered bytes, the command prints them and exits successfully, while the same fetch with --output FILE fails with a checksum mismatch. Hex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the x-hex-message header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror's files. This happens even when the checksum check then fails, because the archive is already on standard output. This issue affects hex: from 0.20.2 before 2.5.2.
    CWE
    • CWE-354 - Improper Validation of Integrity Check Value
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.20.2 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: d1f5a085d9d4748e1f7d195e4bc39ebd77c28d9c , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Package\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.package.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Package\u0027:run/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.20.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Package\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.package.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Package\u0027:run/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "8a14632ca6ba8a8afd2a3f2098bc267c13e13d93",
                      "status": "unaffected"
                    },
                    {
                      "at": "69489f8b74213f03db10169e6e5407e6d5fee512",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "d1f5a085d9d4748e1f7d195e4bc39ebd77c28d9c",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects \u003ccode\u003emix hex.package fetch\u003c/code\u003e with \u003ccode\u003e--output -\u003c/code\u003e when packages are downloaded through a mirror set with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e. Downloads directly from the repository over HTTPS aren\u0027t affected unless TLS verification is broken.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects `mix hex.package fetch` with `--output -` when packages are downloaded through a mirror set with `HEX_MIRROR_URL` or `mirror_url`. Downloads directly from the repository over HTTPS aren\u0027t affected unless TLS verification is broken."
                }
              ],
              "value": "Affects mix hex.package fetch with --output - when packages are downloaded through a mirror set with HEX_MIRROR_URL or mirror_url. Downloads directly from the repository over HTTPS aren\u0027t affected unless TLS verification is broken."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.20.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:01:30.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that \u003ccode\u003emix hex.package fetch PACKAGE VERSION --output -\u003c/code\u003e writes to standard output.\u003c/p\u003e\n\u003cp\u003eHex compares a fetched tarball\u0027s inner and outer checksums with the repository\u0027s signed registry before writing it to a file or unpacking it. The standard output branch of \u003ccode\u003emix hex.package fetch\u003c/code\u003e writes the bytes returned by \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e without that comparison, and \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e doesn\u0027t verify freshly downloaded tarballs itself. When a mirror configured with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e serves altered bytes, the command prints them and exits successfully, while the same fetch with \u003ccode\u003e--output FILE\u003c/code\u003e fails with a checksum mismatch.\u003c/p\u003e\n\u003cp\u003eHex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the \u003ccode\u003ex-hex-message\u003c/code\u003e header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror\u0027s files. This happens even when the checksum check then fails, because the archive is already on standard output.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.20.2 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that `mix hex.package fetch PACKAGE VERSION --output -` writes to standard output.\n\nHex compares a fetched tarball\u0027s inner and outer checksums with the repository\u0027s signed registry before writing it to a file or unpacking it. The standard output branch of `mix hex.package fetch` writes the bytes returned by `Hex.SCM.fetch/3` without that comparison, and `Hex.SCM.fetch/3` doesn\u0027t verify freshly downloaded tarballs itself. When a mirror configured with `HEX_MIRROR_URL` or `mirror_url` serves altered bytes, the command prints them and exits successfully, while the same fetch with `--output FILE` fails with a checksum mismatch.\n\nHex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the `x-hex-message` header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror\u0027s files. This happens even when the checksum check then fails, because the archive is already on standard output.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
                }
              ],
              "value": "Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that mix hex.package fetch PACKAGE VERSION --output - writes to standard output.\n\nHex compares a fetched tarball\u0027s inner and outer checksums with the repository\u0027s signed registry before writing it to a file or unpacking it. The standard output branch of mix hex.package fetch writes the bytes returned by Hex.SCM.fetch/3 without that comparison, and Hex.SCM.fetch/3 doesn\u0027t verify freshly downloaded tarballs itself. When a mirror configured with HEX_MIRROR_URL or mirror_url serves altered bytes, the command prints them and exits successfully, while the same fetch with --output FILE fails with a checksum mismatch.\n\nHex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the x-hex-message header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror\u0027s files. This happens even when the checksum check then fails, because the archive is already on standard output.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-186",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eHex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe \u003ccode\u003emix hex.package fetch --output -\u003c/code\u003e into another tool, such as an unpacker, a vendoring step or an installer, receive whatever the mirror served, so the mirror operator can deliver modified package contents that downstream steps treat as the published release.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "Hex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe `mix hex.package fetch --output -` into another tool, such as an unpacker, a vendoring step or an installer, receive whatever the mirror served, so the mirror operator can deliver modified package contents that downstream steps treat as the published release."
                    }
                  ],
                  "value": "Hex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe mix hex.package fetch --output - into another tool, such as an unpacker, a vendoring step or an installer, receive whatever the mirror served, so the mirror operator can deliver modified package contents that downstream steps treat as the published release."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 6.9,
                "baseSeverity": "MEDIUM",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "HIGH",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-354",
                  "description": "CWE-354 Improper Validation of Integrity Check Value",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:30:14.126Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-98jr-23pm-vj7c"
            },
            {
              "name": "EEF CNA record for CVE-2026-105280",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-105280.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-105280",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-105280"
            },
            {
              "name": "Introducing commit d1f5a08 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/d1f5a085d9d4748e1f7d195e4bc39ebd77c28d9c"
            },
            {
              "name": "Fix commit 8a14632 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/8a14632ca6ba8a8afd2a3f2098bc267c13e13d93"
            },
            {
              "name": "Fix commit 69489f8 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/69489f8b74213f03db10169e6e5407e6d5fee512"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. \u003ccode\u003emix hex.package fetch PACKAGE VERSION --output -\u003c/code\u003e then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. `mix hex.package fetch PACKAGE VERSION --output -` then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. mix hex.package fetch PACKAGE VERSION --output - then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex writes unverified package tarballs to standard output in mix hex.package fetch",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eWrite the tarball to a file with \u003ccode\u003e--output FILE\u003c/code\u003e, which verifies the checksums, and read that file instead of standard output.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Write the tarball to a file with `--output FILE`, which verifies the checksums, and read that file instead of standard output."
                }
              ],
              "value": "Write the tarball to a file with --output FILE, which verifies the checksums, and read that file instead of standard output."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eSet \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e to a server that returns modified bytes for \u003ccode\u003etarballs/decimal-2.4.1.tar\u003c/code\u003e and proxies everything else to repo.hex.pm.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emix hex.package fetch decimal 2.4.1 --output -\u003c/code\u003e prints the modified bytes and exits 0.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emix hex.package fetch decimal 2.4.1 --output decimal.tar\u003c/code\u003e fails with \u003ccode\u003eChecksum mismatch against registry (outer)\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Set `HEX_MIRROR_URL` to a server that returns modified bytes for `tarballs/decimal-2.4.1.tar` and proxies everything else to repo.hex.pm.\n2. `mix hex.package fetch decimal 2.4.1 --output -` prints the modified bytes and exits 0.\n3. `mix hex.package fetch decimal 2.4.1 --output decimal.tar` fails with `Checksum mismatch against registry (outer)`."
                }
              ],
              "value": "* Set HEX_MIRROR_URL to a server that returns modified bytes for tarballs/decimal-2.4.1.tar and proxies everything else to repo.hex.pm.\n* mix hex.package fetch decimal 2.4.1 --output - prints the modified bytes and exits 0.\n* mix hex.package fetch decimal 2.4.1 --output decimal.tar fails with Checksum mismatch against registry (outer)."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003emix hex.package fetch PACKAGE VERSION --output -\u003c/code\u003e calls \u003ccode\u003efetch_tarball!/3\u003c/code\u003e, which calls \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eFor a fresh download, \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e writes the response body to the cache and returns it without comparing it to the registry checksum.\u003c/li\u003e\n\u003cli\u003eThe standard output branch passes those bytes to \u003ccode\u003eIO.binwrite/1\u003c/code\u003e. The file and \u003ccode\u003e--unpack\u003c/code\u003e branches call \u003ccode\u003everify_inner_checksum!/4\u003c/code\u003e and \u003ccode\u003everify_outer_checksum!/4\u003c/code\u003e first.\u003c/li\u003e\n\u003cli\u003eWhile the task runs, Hex prints messages with \u003ccode\u003eHex.Shell.info/1\u003c/code\u003e, which writes to standard output. \u003ccode\u003eHex.Utils.print_error_result/1\u003c/code\u003e prints the body of an error response that way; the update checker calls it when its request for \u003ccode\u003einstalls/hex-1.x.csv\u003c/code\u003e fails, and \u003ccode\u003eHex.Registry.Server\u003c/code\u003e calls it when a registry fetch fails and the cached registry is used. \u003ccode\u003eHex.HTTP\u003c/code\u003e prints the \u003ccode\u003ex-hex-message\u003c/code\u003e warning of each response the same way. These are printed before the tarball is written, so the mirror chooses bytes that come before the tarball on standard output.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `mix hex.package fetch PACKAGE VERSION --output -` calls `fetch_tarball!/3`, which calls `Hex.SCM.fetch/3`.\n2. For a fresh download, `Hex.SCM.fetch/3` writes the response body to the cache and returns it without comparing it to the registry checksum.\n3. The standard output branch passes those bytes to `IO.binwrite/1`. The file and `--unpack` branches call `verify_inner_checksum!/4` and `verify_outer_checksum!/4` first.\n4. While the task runs, Hex prints messages with `Hex.Shell.info/1`, which writes to standard output. `Hex.Utils.print_error_result/1` prints the body of an error response that way; the update checker calls it when its request for `installs/hex-1.x.csv` fails, and `Hex.Registry.Server` calls it when a registry fetch fails and the cached registry is used. `Hex.HTTP` prints the `x-hex-message` warning of each response the same way. These are printed before the tarball is written, so the mirror chooses bytes that come before the tarball on standard output."
                }
              ],
              "value": "* mix hex.package fetch PACKAGE VERSION --output - calls fetch_tarball!/3, which calls Hex.SCM.fetch/3.\n* For a fresh download, Hex.SCM.fetch/3 writes the response body to the cache and returns it without comparing it to the registry checksum.\n* The standard output branch passes those bytes to IO.binwrite/1. The file and --unpack branches call verify_inner_checksum!/4 and verify_outer_checksum!/4 first.\n* While the task runs, Hex prints messages with Hex.Shell.info/1, which writes to standard output. Hex.Utils.print_error_result/1 prints the body of an error response that way; the update checker calls it when its request for installs/hex-1.x.csv fails, and Hex.Registry.Server calls it when a registry fetch fails and the cached registry is used. Hex.HTTP prints the x-hex-message warning of each response the same way. These are printed before the tarball is written, so the mirror chooses bytes that come before the tarball on standard output."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-105280",
        "datePublished": "2026-10-12T15:30:14.126Z",
        "dateReserved": "2026-10-08T13:45:02.134Z",
        "dateUpdated": "2026-10-12T15:30:14.126Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-103503 (GCVE-0-2026-103503)

    Vulnerability from nvd – Published: 2026-10-12 15:17 – Updated: 2026-10-12 15:17
    VLAI
    Title
    Hex trusts its bundled CA certificates when cacerts_path is set
    Summary
    Improper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex's bundled CA store, to impersonate that host to users who set cacerts_path to a CA store that leaves that CA out. cacerts_path (HEX_CACERTS_PATH) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. Hex.HTTP.SSL.ssl_opts/1 passes the configured store as the cacerts option, but builds the partial_chain callback from the bundled store whether cacerts_path is set or not. Hex.HTTP.SSL.partial_chain/2 accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn't contain that CA. Hostname verification still applies. This issue affects hex: from 0.20.2 before 2.5.2.
    CWE
    • CWE-295 - Improper Certificate Validation
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.20.2 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: c9b26a46928bfcd546773571e09c1d05f4cd9fb7 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP.SSL\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/http/ssl.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:ssl_opts/1"
                },
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:partial_chain/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.20.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP.SSL\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/http/ssl.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:ssl_opts/1"
                },
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:partial_chain/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "5f5a2136c7cf5991b6e8a30d645ca9f8e74b0785",
                      "status": "unaffected"
                    },
                    {
                      "at": "6232a6498015e559743bec4f4fbec9138837cec8",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "c9b26a46928bfcd546773571e09c1d05f4cd9fb7",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects users who set \u003ccode\u003ecacerts_path\u003c/code\u003e or \u003ccode\u003eHEX_CACERTS_PATH\u003c/code\u003e to a CA store that leaves out some of the CAs bundled with Hex. Users who don\u0027t set it trust the bundled store already and aren\u0027t affected.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects users who set `cacerts_path` or `HEX_CACERTS_PATH` to a CA store that leaves out some of the CAs bundled with Hex. Users who don\u0027t set it trust the bundled store already and aren\u0027t affected."
                }
              ],
              "value": "Affects users who set cacerts_path or HEX_CACERTS_PATH to a CA store that leaves out some of the CAs bundled with Hex. Users who don\u0027t set it trust the bundled store already and aren\u0027t affected."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.20.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T12:59:48.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex\u0027s bundled CA store, to impersonate that host to users who set \u003ccode\u003ecacerts_path\u003c/code\u003e to a CA store that leaves that CA out.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecacerts_path\u003c/code\u003e (\u003ccode\u003eHEX_CACERTS_PATH\u003c/code\u003e) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. \u003ccode\u003eHex.HTTP.SSL.ssl_opts/1\u003c/code\u003e passes the configured store as the \u003ccode\u003ecacerts\u003c/code\u003e option, but builds the \u003ccode\u003epartial_chain\u003c/code\u003e callback from the bundled store whether \u003ccode\u003ecacerts_path\u003c/code\u003e is set or not. \u003ccode\u003eHex.HTTP.SSL.partial_chain/2\u003c/code\u003e accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn\u0027t contain that CA. Hostname verification still applies.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.20.2 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex\u0027s bundled CA store, to impersonate that host to users who set `cacerts_path` to a CA store that leaves that CA out.\n\n`cacerts_path` (`HEX_CACERTS_PATH`) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. `Hex.HTTP.SSL.ssl_opts/1` passes the configured store as the `cacerts` option, but builds the `partial_chain` callback from the bundled store whether `cacerts_path` is set or not. `Hex.HTTP.SSL.partial_chain/2` accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn\u0027t contain that CA. Hostname verification still applies.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
                }
              ],
              "value": "Improper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex\u0027s bundled CA store, to impersonate that host to users who set cacerts_path to a CA store that leaves that CA out.\n\ncacerts_path (HEX_CACERTS_PATH) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. Hex.HTTP.SSL.ssl_opts/1 passes the configured store as the cacerts option, but builds the partial_chain callback from the bundled store whether cacerts_path is set or not. Hex.HTTP.SSL.partial_chain/2 accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn\u0027t contain that CA. Hostname verification still applies.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-94",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eUsers set \u003ccode\u003ecacerts_path\u003c/code\u003e to limit which CAs can authenticate Hex\u0027s servers, for example to their organization\u0027s internal CA. Every CA in Hex\u0027s bundled store can still authenticate those servers, so a certificate mis-issued by one of those CAs, or obtained through compromised domain validation, lets an attacker on the network path impersonate hex.pm, repo.hex.pm, a self-hosted repository or a mirror. The attacker receives the API keys, OAuth tokens and repository keys Hex sends, and can alter API responses. Registry signatures and package checksums still prevent changes to registry contents and packages.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "Users set `cacerts_path` to limit which CAs can authenticate Hex\u0027s servers, for example to their organization\u0027s internal CA. Every CA in Hex\u0027s bundled store can still authenticate those servers, so a certificate mis-issued by one of those CAs, or obtained through compromised domain validation, lets an attacker on the network path impersonate hex.pm, repo.hex.pm, a self-hosted repository or a mirror. The attacker receives the API keys, OAuth tokens and repository keys Hex sends, and can alter API responses. Registry signatures and package checksums still prevent changes to registry contents and packages."
                    }
                  ],
                  "value": "Users set cacerts_path to limit which CAs can authenticate Hex\u0027s servers, for example to their organization\u0027s internal CA. Every CA in Hex\u0027s bundled store can still authenticate those servers, so a certificate mis-issued by one of those CAs, or obtained through compromised domain validation, lets an attacker on the network path impersonate hex.pm, repo.hex.pm, a self-hosted repository or a mirror. The attacker receives the API keys, OAuth tokens and repository keys Hex sends, and can alter API responses. Registry signatures and package checksums still prevent changes to registry contents and packages."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "HIGH",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 5.9,
                "baseSeverity": "MEDIUM",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:A/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "LOW",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-295",
                  "description": "CWE-295 Improper Certificate Validation",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:17:45.545Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-rw8q-hg7m-cxgr"
            },
            {
              "name": "EEF CNA record for CVE-2026-103503",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-103503.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-103503",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-103503"
            },
            {
              "name": "Introducing commit c9b26a4 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/c9b26a46928bfcd546773571e09c1d05f4cd9fb7"
            },
            {
              "name": "Fix commit 5f5a213 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/5f5a2136c7cf5991b6e8a30d645ca9f8e74b0785"
            },
            {
              "name": "Fix commit 6232a64 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/6232a6498015e559743bec4f4fbec9138837cec8"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. With \u003ccode\u003ecacerts_path\u003c/code\u003e (\u003ccode\u003eHEX_CACERTS_PATH\u003c/code\u003e) set, Hex then only accepts server certificates that chain to a CA in that file, and it doesn\u0027t trust copies of CA certificates sent by the server.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. With `cacerts_path` (`HEX_CACERTS_PATH`) set, Hex then only accepts server certificates that chain to a CA in that file, and it doesn\u0027t trust copies of CA certificates sent by the server."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. With cacerts_path (HEX_CACERTS_PATH) set, Hex then only accepts server certificates that chain to a CA in that file, and it doesn\u0027t trust copies of CA certificates sent by the server."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex trusts its bundled CA certificates when cacerts_path is set",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eThere\u0027s no Hex configuration that stops the bundled CAs from being trusted.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "There\u0027s no Hex configuration that stops the bundled CAs from being trusted."
                }
              ],
              "value": "There\u0027s no Hex configuration that stops the bundled CAs from being trusted."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eCreate a PEM file that contains only an unrelated test CA certificate and set \u003ccode\u003ecacerts_path\u003c/code\u003e to it.\u003c/li\u003e\n\u003cli\u003eOpen a TLS connection to hex.pm with the options from \u003ccode\u003eHex.HTTP.SSL.ssl_opts(\"https://hex.pm\")\u003c/code\u003e. The handshake succeeds, and the accepted chain leads to ISRG Root X2 cross-signed by ISRG Root X1, neither of which is in the PEM file.\u003c/li\u003e\n\u003cli\u003eRemove the \u003ccode\u003epartial_chain\u003c/code\u003e option and connect again. The handshake fails with \u003ccode\u003eunknown_ca\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Create a PEM file that contains only an unrelated test CA certificate and set `cacerts_path` to it.\n2. Open a TLS connection to hex.pm with the options from `Hex.HTTP.SSL.ssl_opts(\"https://hex.pm\")`. The handshake succeeds, and the accepted chain leads to ISRG Root X2 cross-signed by ISRG Root X1, neither of which is in the PEM file.\n3. Remove the `partial_chain` option and connect again. The handshake fails with `unknown_ca`."
                }
              ],
              "value": "* Create a PEM file that contains only an unrelated test CA certificate and set cacerts_path to it.\n* Open a TLS connection to hex.pm with the options from Hex.HTTP.SSL.ssl_opts(\"https://hex.pm\"). The handshake succeeds, and the accepted chain leads to ISRG Root X2 cross-signed by ISRG Root X1, neither of which is in the PEM file.\n* Remove the partial_chain option and connect again. The handshake fails with unknown_ca."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003eHex.HTTP.SSL.get_ca_certs/0\u003c/code\u003e returns the certificates from \u003ccode\u003ecacerts_path\u003c/code\u003e when it\u0027s set, and \u003ccode\u003essl_opts/1\u003c/code\u003e passes them as \u003ccode\u003ecacerts\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003essl_opts/1\u003c/code\u003e sets \u003ccode\u003epartial_chain\u003c/code\u003e to \u003ccode\u003e\u0026amp;partial_chain(Certs.cacerts(), \u0026amp;1)\u003c/code\u003e, which always uses the bundled store.\u003c/li\u003e\n\u003cli\u003eWhen the server\u0027s chain doesn\u0027t lead to a certificate in \u003ccode\u003ecacerts\u003c/code\u003e, OTP calls \u003ccode\u003epartial_chain\u003c/code\u003e with the chain. \u003ccode\u003epartial_chain/2\u003c/code\u003e returns \u003ccode\u003e{:trusted_ca, der}\u003c/code\u003e for the first certificate whose public key matches a bundled CA certificate, and OTP validates the chain with that certificate as the trust anchor.\u003c/li\u003e\n\u003cli\u003eChain validation and the hostname check from \u003ccode\u003ecustomize_hostname_check/1\u003c/code\u003e still run, so the attacker needs a certificate for the requested host that chains to a bundled CA.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `Hex.HTTP.SSL.get_ca_certs/0` returns the certificates from `cacerts_path` when it\u0027s set, and `ssl_opts/1` passes them as `cacerts`.\n2. `ssl_opts/1` sets `partial_chain` to `\u0026partial_chain(Certs.cacerts(), \u00261)`, which always uses the bundled store.\n3. When the server\u0027s chain doesn\u0027t lead to a certificate in `cacerts`, OTP calls `partial_chain` with the chain. `partial_chain/2` returns `{:trusted_ca, der}` for the first certificate whose public key matches a bundled CA certificate, and OTP validates the chain with that certificate as the trust anchor.\n4. Chain validation and the hostname check from `customize_hostname_check/1` still run, so the attacker needs a certificate for the requested host that chains to a bundled CA."
                }
              ],
              "value": "* Hex.HTTP.SSL.get_ca_certs/0 returns the certificates from cacerts_path when it\u0027s set, and ssl_opts/1 passes them as cacerts.\n* ssl_opts/1 sets partial_chain to \u0026partial_chain(Certs.cacerts(), \u00261), which always uses the bundled store.\n* When the server\u0027s chain doesn\u0027t lead to a certificate in cacerts, OTP calls partial_chain with the chain. partial_chain/2 returns {:trusted_ca, der} for the first certificate whose public key matches a bundled CA certificate, and OTP validates the chain with that certificate as the trust anchor.\n* Chain validation and the hostname check from customize_hostname_check/1 still run, so the attacker needs a certificate for the requested host that chains to a bundled CA."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-103503",
        "datePublished": "2026-10-12T15:17:45.545Z",
        "dateReserved": "2026-10-08T15:45:02.372Z",
        "dateUpdated": "2026-10-12T15:17:45.545Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-32148 (GCVE-0-2026-32148)

    Vulnerability from nvd – Published: 2026-04-30 18:17 – Updated: 2026-05-01 04:33
    VLAI
    Title
    Lockfile checksums not verified in Hex allows dependency integrity bypass
    Summary
    Insufficient Verification of Data Authenticity vulnerability in hexpm hex (Hex.RemoteConverger module) allows dependency integrity bypass via unverified lockfile checksums. Hex stores checksums for dependencies in the mix.lock file to ensure reproducible and integrity-checked builds. However, Hex.RemoteConverger.verify_resolved/2 never executes checksum verification because the lock data returned by Hex.Utils.lock/1 uses string-based dependency names, while the verification logic compares against atom-based names. This type mismatch causes the verification code path to be silently skipped. Checksums are still validated when packages are initially downloaded from the registry, but mismatches between the lockfile and resolved dependencies are not detected. An attacker who can influence cached packages (e.g., via local cache poisoning or a compromised registry) can provide modified dependency contents that will be accepted without detection. The mix.lock file is silently rewritten with the checksum values from the registry, erasing evidence of tampering. This issue affects hex: from 0.16.0 before 2.4.2.
    SSVC
    Exploitation: poc Automatable: no Technical Impact: total
    CISA Coordinator · CISA-ADP (v2.0.3)
    Decision recorded 2026-04-30 19:03 UTC
    CWE
    • CWE-354 - Improper Validation of Integrity Check Value
    • CWE-494 - Download of Code Without Integrity Check
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.16.0 , < 2.4.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: e01576f28c64af9fae6eb17e2dad30f6efcb303c , < d7528c8199a1144511508bf3a6460026a5a14c8e (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-32148",
                    "options": [
                      {
                        "Exploitation": "poc"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "total"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-04-30T19:03:06.385106Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-04-30T19:03:24.858Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "references": [
              {
                "tags": [
                  "exploit"
                ],
                "url": "https://github.com/hexpm/hex/security/advisories/GHSA-hmv9-4mfr-m92v"
              }
            ],
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=git%20https:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:verify_resolved/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.4.2",
                  "status": "affected",
                  "version": "0.16.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:verify_resolved/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex.git",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "d7528c8199a1144511508bf3a6460026a5a14c8e",
                  "status": "affected",
                  "version": "e01576f28c64af9fae6eb17e2dad30f6efcb303c",
                  "versionType": "git"
                }
              ]
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.4.2",
                      "versionStartIncluding": "0.16.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Paul Fleischer"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Jonatan M\u00e4nnchen / EEF"
            },
            {
              "lang": "en",
              "type": "remediation reviewer",
              "value": "Eric Meadows-J\u00f6nsson / Hex.pm"
            }
          ],
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "Insufficient Verification of Data Authenticity vulnerability in hexpm hex (\u003ctt\u003eHex.RemoteConverger\u003c/tt\u003e module) allows dependency integrity bypass via unverified lockfile checksums.\u003cp\u003eHex stores checksums for dependencies in the \u003ctt\u003emix.lock\u003c/tt\u003e file to ensure reproducible and integrity-checked builds. However, \u003ctt\u003eHex.RemoteConverger.verify_resolved/2\u003c/tt\u003e never executes checksum verification because the lock data returned by \u003ctt\u003eHex.Utils.lock/1\u003c/tt\u003e uses string-based dependency names, while the verification logic compares against atom-based names. This type mismatch causes the verification code path to be silently skipped. Checksums are still validated when packages are initially downloaded from the registry, but mismatches between the lockfile and resolved dependencies are not detected.\u003c/p\u003e\u003cp\u003eAn attacker who can influence cached packages (e.g., via local cache poisoning or a compromised registry) can provide modified dependency contents that will be accepted without detection. The \u003ctt\u003emix.lock\u003c/tt\u003e file is silently rewritten with the checksum values from the registry, erasing evidence of tampering.\u003c/p\u003e\u003cp\u003eThis issue affects hex: from 0.16.0 before 2.4.2.\u003c/p\u003e"
                }
              ],
              "value": "Insufficient Verification of Data Authenticity vulnerability in hexpm hex (Hex.RemoteConverger module) allows dependency integrity bypass via unverified lockfile checksums.\n\nHex stores checksums for dependencies in the mix.lock file to ensure reproducible and integrity-checked builds. However, Hex.RemoteConverger.verify_resolved/2 never executes checksum verification because the lock data returned by Hex.Utils.lock/1 uses string-based dependency names, while the verification logic compares against atom-based names. This type mismatch causes the verification code path to be silently skipped. Checksums are still validated when packages are initially downloaded from the registry, but mismatches between the lockfile and resolved dependencies are not detected.\n\nAn attacker who can influence cached packages (e.g., via local cache poisoning or a compromised registry) can provide modified dependency contents that will be accepted without detection. The mix.lock file is silently rewritten with the checksum values from the registry, erasing evidence of tampering.\n\nThis issue affects hex: from 0.16.0 before 2.4.2."
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 8.9,
                "baseSeverity": "HIGH",
                "exploitMaturity": "NOT_DEFINED",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "HIGH",
                "subConfidentialityImpact": "HIGH",
                "subIntegrityImpact": "HIGH",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-354",
                  "description": "CWE-354 Improper Validation of Integrity Check Value",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            },
            {
              "descriptions": [
                {
                  "cweId": "CWE-494",
                  "description": "CWE-494 Download of Code Without Integrity Check",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-05-01T04:33:38.198Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "tags": [
                "vendor-advisory",
                "related"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-hmv9-4mfr-m92v"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-32148.html"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-32148"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/d7528c8199a1144511508bf3a6460026a5a14c8e"
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "Lockfile checksums not verified in Hex allows dependency integrity bypass",
          "x_generator": {
            "engine": "cvelib 1.8.0"
          }
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-32148",
        "datePublished": "2026-04-30T18:17:03.783Z",
        "dateReserved": "2026-03-10T22:37:29.213Z",
        "dateUpdated": "2026-05-01T04:33:38.198Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-21619 (GCVE-0-2026-21619)

    Vulnerability from nvd – Published: 2026-02-27 17:57 – Updated: 2026-05-27 15:40
    VLAI
    Title
    Unsafe Deserialization of Erlang Terms in hex_core
    Summary
    Uncontrolled Resource Consumption, Deserialization of Untrusted Data vulnerability in hexpm hex_core (hex_api modules), hexpm hex (mix_hex_api modules), erlang rebar3 (r3_hex_api modules) allows Object Injection, Excessive Allocation. This vulnerability is associated with program files src/hex_api.erl, src/mix_hex_api.erl, apps/rebar/src/vendored/r3_hex_api.erl and program routines hex_core:request/4, mix_hex_api:request/4, r3_hex_api:request/4. This issue affects hex_core: from 0.1.0 before 0.12.1; hex: from 2.3.0 before 2.3.2; rebar3: from 3.9.1 before 3.27.0.
    SSVC
    Exploitation: none Automatable: no Technical Impact: partial
    CISA Coordinator · CISA-ADP (v2.0.3)
    Decision recorded 2026-02-27 19:08 UTC
    CWE
    • CWE-400 - Uncontrolled Resource Consumption
    • CWE-502 - Deserialization of Untrusted Data
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex_core Affected: eb327f8edfe45507351e38cc0805aa12fa647f0b , < cdf726095bca85ad2549d146df1e831ae93c2b13 (git)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 0.1.0 , < 0.12.1 (semver)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 314546ac432229518714cc8e3336e916b9da6305 , < 636739f3322514e9303ca335fb630696fcbb3c95 (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 2.3.0 , < 2.3.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 209c02ec57c2cc3207ee0174c3af3675b8dc8f79 , < 1d4478f527e373de0b225951e53115450e0d9b9d (git)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 3.9.1 , < 3.27.0 (semver)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-21619",
                    "options": [
                      {
                        "Exploitation": "none"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "partial"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-02-27T19:08:49.652728Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-02-27T19:08:57.019Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_api"
              ],
              "packageName": "hexpm/hex_core",
              "packageURL": "pkg:github/hexpm/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_core:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "cdf726095bca85ad2549d146df1e831ae93c2b13",
                  "status": "affected",
                  "version": "eb327f8edfe45507351e38cc0805aa12fa647f0b",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_api"
              ],
              "packageName": "hex_core",
              "packageURL": "pkg:hex/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_core:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "0.12.1",
                  "status": "affected",
                  "version": "0.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_api"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "636739f3322514e9303ca335fb630696fcbb3c95",
                  "status": "affected",
                  "version": "314546ac432229518714cc8e3336e916b9da6305",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_api"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex.git\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.3.2",
                  "status": "affected",
                  "version": "2.3.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_api"
              ],
              "packageName": "erlang/rebar3",
              "packageURL": "pkg:github/erlang/rebar3",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "1d4478f527e373de0b225951e53115450e0d9b9d",
                  "status": "affected",
                  "version": "209c02ec57c2cc3207ee0174c3af3675b8dc8f79",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_api"
              ],
              "packageName": "rebar3",
              "packageURL": "pkg:otp/rebar3?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Frebar3.git\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Frebar3.git",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "3.27.0",
                  "status": "affected",
                  "version": "3.9.1",
                  "versionType": "semver"
                }
              ]
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.12.1",
                      "versionStartIncluding": "0.1.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "AND"
                },
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.3.2",
                      "versionStartIncluding": "2.3.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "AND"
                },
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "3.27.0",
                      "versionStartIncluding": "3.9.1",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "AND"
                }
              ],
              "operator": "OR"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Michael Lubas / Paraxial.io"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Jonatan M\u00e4nnchen / EEF"
            },
            {
              "lang": "en",
              "type": "remediation reviewer",
              "value": "Eric Meadows-J\u00f6nsson / Hex.pm"
            }
          ],
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "Uncontrolled Resource Consumption, Deserialization of Untrusted Data vulnerability in hexpm hex_core (hex_api modules), hexpm hex (mix_hex_api modules), erlang rebar3 (r3_hex_api modules) allows Object Injection, Excessive Allocation.\u003cp\u003e This vulnerability is associated with program files \u003ctt\u003esrc/hex_api.erl\u003c/tt\u003e, \u003ctt\u003esrc/mix_hex_api.erl\u003c/tt\u003e, \u003ctt\u003eapps/rebar/src/vendored/r3_hex_api.erl\u003c/tt\u003e and program routines \u003ctt\u003ehex_core:request/4\u003c/tt\u003e, \u003ctt\u003emix_hex_api:request/4\u003c/tt\u003e, \u003ctt\u003er3_hex_api:request/4\u003c/tt\u003e.\u003c/p\u003e\u003cp\u003eThis issue affects hex_core: from 0.1.0 before 0.12.1; hex: from 2.3.0 before 2.3.2; rebar3: from 3.9.1 before 3.27.0.\u003c/p\u003e"
                }
              ],
              "value": "Uncontrolled Resource Consumption, Deserialization of Untrusted Data vulnerability in hexpm hex_core (hex_api modules), hexpm hex (mix_hex_api modules), erlang rebar3 (r3_hex_api modules) allows Object Injection, Excessive Allocation. This vulnerability is associated with program files src/hex_api.erl, src/mix_hex_api.erl, apps/rebar/src/vendored/r3_hex_api.erl and program routines hex_core:request/4, mix_hex_api:request/4, r3_hex_api:request/4.\n\nThis issue affects hex_core: from 0.1.0 before 0.12.1; hex: from 2.3.0 before 2.3.2; rebar3: from 3.9.1 before 3.27.0."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-586",
              "descriptions": [
                {
                  "lang": "en",
                  "value": "CAPEC-586 Object Injection"
                }
              ]
            },
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "value": "CAPEC-130 Excessive Allocation"
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2,
                "baseSeverity": "LOW",
                "exploitMaturity": "NOT_DEFINED",
                "privilegesRequired": "LOW",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "LOW",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-400",
                  "description": "CWE-400 Uncontrolled Resource Consumption",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            },
            {
              "descriptions": [
                {
                  "cweId": "CWE-502",
                  "description": "CWE-502 Deserialization of Untrusted Data",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-05-27T15:40:33.166Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "tags": [
                "vendor-advisory",
                "related"
              ],
              "url": "https://github.com/hexpm/hex_core/security/advisories/GHSA-hx9w-f2w9-9g96"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-21619.html"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-21619"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/cdf726095bca85ad2549d146df1e831ae93c2b13"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/636739f3322514e9303ca335fb630696fcbb3c95"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/erlang/rebar3/commit/1d4478f527e373de0b225951e53115450e0d9b9d"
            }
          ],
          "source": {
            "discovery": "INTERNAL"
          },
          "title": "Unsafe Deserialization of Erlang Terms in hex_core",
          "x_generator": {
            "engine": "Vulnogram 0.5.0"
          }
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-21619",
        "datePublished": "2026-02-27T17:57:11.513Z",
        "dateReserved": "2026-01-01T03:46:45.933Z",
        "dateUpdated": "2026-05-27T15:40:33.166Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-96596 (GCVE-0-2026-96596)

    Vulnerability from cvelistv5 – Published: 2026-10-14 16:56 – Updated: 2026-10-14 21:46
    VLAI
    Title
    erl_tar:extract/2 loops forever on a GNU sparse member with a trailing hole
    Summary
    Loop with Unreachable Exit Condition ('Infinite Loop') vulnerability in Erlang OTP stdlib (erl_tar module), hexpm hex_core (hex_erl_tar module), hexpm hex (mix_hex_erl_tar module) and erlang rebar3 (r3_hex_erl_tar module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member. When erl_tar:extract/1,2 writes a member to disk, erl_tar:stream_to_file_loop/3 reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, erl_tar:do_sparse_read/3 matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The {max_size, N} option prevents this only when N is below the real size of the member. Extraction with the memory option is not affected. hex_core ships its own copy of erl_tar as hex_erl_tar, and Hex and rebar3 ship hex_core with prefixed module names (mix_hex_erl_tar and r3_hex_erl_tar). These copies contain the same code and do not call stdlib's erl_tar, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3. This issue affects OTP from OTP 29.0 before OTP 29.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1.
    CWE
    • CWE-835 - Loop with Unreachable Exit Condition ('Infinite Loop')
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    Erlang OTP Affected: 29.0 , < 29.1.2 (otp)
        cpe:2.3:a:erlang:erlang\/otp:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Erlang OTP Affected: 8.0 , < 8.1.1 (otp)
        cpe:2.3:a:erlang:erlang\/otp:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Erlang OTP Affected: fbf2c7194f6fce4b7b66dc0bcaa4f6b4b85e088f , < 3086307f311b78b38644a7787a3aca6a3f95a9d5 (git)
        cpe:2.3:a:erlang:erlang\/otp:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 3.27.1 , < * (semver)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 23dbdb5d1f87f56902aef296c88a20049cd0c6e4 , < * (git)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 0.14.0 , < 0.20.1 (semver)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 13bb9fbba418a406af614790b8d5cd458259ee70 , < a2ece683e6e88a3ec95ad20b09aca426e08b372e (git)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 2.4.2 , < 2.5.3 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 5543a1919c709d8eb2b317f62aad76ca1eed375c , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Date Public
    2026-10-14 16:56
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "erl_tar"
              ],
              "packageName": "otp",
              "packageURL": "pkg:software-id/erlang.org/otp",
              "product": "OTP",
              "programFiles": [
                "lib/stdlib/src/erl_tar.erl"
              ],
              "programRoutines": [
                {
                  "name": "erl_tar:do_sparse_read/3"
                },
                {
                  "name": "erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "erl_tar:extract/1"
                },
                {
                  "name": "erl_tar:extract/2"
                }
              ],
              "vendor": "Erlang",
              "versions": [
                {
                  "lessThan": "29.1.2",
                  "status": "affected",
                  "version": "29.0",
                  "versionType": "otp"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "erl_tar"
              ],
              "packageName": "stdlib",
              "packageURL": "pkg:otp/stdlib?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Fotp\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Fotp.git",
              "product": "OTP",
              "programFiles": [
                "src/erl_tar.erl"
              ],
              "programRoutines": [
                {
                  "name": "erl_tar:do_sparse_read/3"
                },
                {
                  "name": "erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "erl_tar:extract/1"
                },
                {
                  "name": "erl_tar:extract/2"
                }
              ],
              "repo": "https://github.com/erlang/otp",
              "vendor": "Erlang",
              "versions": [
                {
                  "lessThan": "8.1.1",
                  "status": "affected",
                  "version": "8.0",
                  "versionType": "otp"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "erl_tar"
              ],
              "packageName": "erlang/otp",
              "packageURL": "pkg:github/erlang/otp",
              "product": "OTP",
              "programFiles": [
                "lib/stdlib/src/erl_tar.erl"
              ],
              "programRoutines": [
                {
                  "name": "erl_tar:do_sparse_read/3"
                },
                {
                  "name": "erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "erl_tar:extract/1"
                },
                {
                  "name": "erl_tar:extract/2"
                }
              ],
              "repo": "https://github.com/erlang/otp",
              "vendor": "Erlang",
              "versions": [
                {
                  "lessThan": "3086307f311b78b38644a7787a3aca6a3f95a9d5",
                  "status": "affected",
                  "version": "fbf2c7194f6fce4b7b66dc0bcaa4f6b4b85e088f",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_erl_tar",
                "r3_hex_tarball"
              ],
              "packageName": "rebar3",
              "packageURL": "pkg:otp/rebar3?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Frebar3\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Frebar3.git",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_erl_tar.erl",
                "apps/rebar/src/vendored/r3_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "r3_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "r3_hex_erl_tar:extract/1"
                },
                {
                  "name": "r3_hex_erl_tar:extract/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/3"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "*",
                  "status": "affected",
                  "version": "3.27.1",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_erl_tar",
                "r3_hex_tarball"
              ],
              "packageName": "erlang/rebar3",
              "packageURL": "pkg:github/erlang/rebar3",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_erl_tar.erl",
                "apps/rebar/src/vendored/r3_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "r3_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "r3_hex_erl_tar:extract/1"
                },
                {
                  "name": "r3_hex_erl_tar:extract/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/2"
                },
                {
                  "name": "r3_hex_tarball:unpack/3"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "r3_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "*",
                  "status": "affected",
                  "version": "23dbdb5d1f87f56902aef296c88a20049cd0c6e4",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_erl_tar",
                "hex_tarball"
              ],
              "packageName": "hex_core",
              "packageURL": "pkg:hex/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_erl_tar.erl",
                "src/hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "hex_erl_tar:extract/1"
                },
                {
                  "name": "hex_erl_tar:extract/2"
                },
                {
                  "name": "hex_tarball:unpack/2"
                },
                {
                  "name": "hex_tarball:unpack/3"
                },
                {
                  "name": "hex_tarball:unpack_docs/2"
                },
                {
                  "name": "hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "0.20.1",
                  "status": "affected",
                  "version": "0.14.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_erl_tar",
                "hex_tarball"
              ],
              "packageName": "hexpm/hex_core",
              "packageURL": "pkg:github/hexpm/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_erl_tar.erl",
                "src/hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "hex_erl_tar:extract/1"
                },
                {
                  "name": "hex_erl_tar:extract/2"
                },
                {
                  "name": "hex_tarball:unpack/2"
                },
                {
                  "name": "hex_tarball:unpack/3"
                },
                {
                  "name": "hex_tarball:unpack_docs/2"
                },
                {
                  "name": "hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "a2ece683e6e88a3ec95ad20b09aca426e08b372e",
                  "status": "affected",
                  "version": "13bb9fbba418a406af614790b8d5cd458259ee70",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_erl_tar",
                "mix_hex_tarball"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_erl_tar.erl",
                "src/mix_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "mix_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "mix_hex_erl_tar:extract/1"
                },
                {
                  "name": "mix_hex_erl_tar:extract/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/3"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.3",
                  "status": "affected",
                  "version": "2.4.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_erl_tar",
                "mix_hex_tarball"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_erl_tar.erl",
                "src/mix_hex_tarball.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_erl_tar:do_sparse_read/3"
                },
                {
                  "name": "mix_hex_erl_tar:stream_to_file_loop/3"
                },
                {
                  "name": "mix_hex_erl_tar:extract/1"
                },
                {
                  "name": "mix_hex_erl_tar:extract/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/2"
                },
                {
                  "name": "mix_hex_tarball:unpack/3"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/2"
                },
                {
                  "name": "mix_hex_tarball:unpack_docs/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "8e1067131a13949eff30623f31648a945ffd5418",
                      "status": "unaffected"
                    },
                    {
                      "at": "7847c23d09ab52113614c3718e1e7d368743da5d",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "5543a1919c709d8eb2b317f62aad76ca1eed375c",
                  "versionType": "git"
                }
              ]
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:erlang:erlang\\/otp:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "29.1.2",
                      "versionStartIncluding": "29.0",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*",
                      "versionStartIncluding": "3.27.1",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.20.1",
                      "versionStartIncluding": "0.14.0",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.3",
                      "versionStartIncluding": "2.4.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "reporter",
              "value": "Eric Meadows-J\u00f6nsson"
            }
          ],
          "dateAssigned": "2026-10-07T13:11:38.000Z",
          "datePublic": "2026-10-14T16:56:18.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eLoop with Unreachable Exit Condition (\u0027Infinite Loop\u0027) vulnerability in Erlang OTP stdlib (\u003ccode\u003eerl_tar\u003c/code\u003e module), hexpm hex_core (\u003ccode\u003ehex_erl_tar\u003c/code\u003e module), hexpm hex (\u003ccode\u003emix_hex_erl_tar\u003c/code\u003e module) and erlang rebar3 (\u003ccode\u003er3_hex_erl_tar\u003c/code\u003e module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member.\u003c/p\u003e\n\u003cp\u003eWhen \u003ccode\u003eerl_tar:extract/1,2\u003c/code\u003e writes a member to disk, \u003ccode\u003eerl_tar:stream_to_file_loop/3\u003c/code\u003e reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, \u003ccode\u003eerl_tar:do_sparse_read/3\u003c/code\u003e matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The \u003ccode\u003e{max_size, N}\u003c/code\u003e option prevents this only when N is below the real size of the member. Extraction with the \u003ccode\u003ememory\u003c/code\u003e option is not affected.\u003c/p\u003e\n\u003cp\u003ehex_core ships its own copy of \u003ccode\u003eerl_tar\u003c/code\u003e as \u003ccode\u003ehex_erl_tar\u003c/code\u003e, and Hex and rebar3 ship hex_core with prefixed module names (\u003ccode\u003emix_hex_erl_tar\u003c/code\u003e and \u003ccode\u003er3_hex_erl_tar\u003c/code\u003e). These copies contain the same code and do not call stdlib\u0027s \u003ccode\u003eerl_tar\u003c/code\u003e, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3.\u003c/p\u003e\n\u003cp\u003eThis issue affects OTP from OTP\u0026nbsp;29.0 before OTP\u0026nbsp;29.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027) vulnerability in Erlang OTP stdlib (`erl_tar` module), hexpm hex_core (`hex_erl_tar` module), hexpm hex (`mix_hex_erl_tar` module) and erlang rebar3 (`r3_hex_erl_tar` module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member.\n\nWhen `erl_tar:extract/1,2` writes a member to disk, `erl_tar:stream_to_file_loop/3` reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, `erl_tar:do_sparse_read/3` matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The `{max_size, N}` option prevents this only when N is below the real size of the member. Extraction with the `memory` option is not affected.\n\nhex_core ships its own copy of `erl_tar` as `hex_erl_tar`, and Hex and rebar3 ship hex_core with prefixed module names (`mix_hex_erl_tar` and `r3_hex_erl_tar`). These copies contain the same code and do not call stdlib\u0027s `erl_tar`, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3.\n\nThis issue affects OTP from OTP\u00a029.0 before OTP\u00a029.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1."
                }
              ],
              "value": "Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027) vulnerability in Erlang OTP stdlib (erl_tar module), hexpm hex_core (hex_erl_tar module), hexpm hex (mix_hex_erl_tar module) and erlang rebar3 (r3_hex_erl_tar module) allows an attacker who supplies a tar archive to cause a denial of service via a crafted GNU sparse member.\n\nWhen erl_tar:extract/1,2 writes a member to disk, erl_tar:stream_to_file_loop/3 reads it in chunks of 65536 bytes by default. For a GNU sparse member whose sparse map ends before its real size, erl_tar:do_sparse_read/3 matches its trailing-hole clause before its zero-length clause. After the chunk is used up, the trailing-hole clause reads zero bytes, does not advance the position, and recurses forever. A 2048-byte archive keeps the extracting process and one scheduler busy until the process is killed. The {max_size, N} option prevents this only when N is below the real size of the member. Extraction with the memory option is not affected.\n\nhex_core ships its own copy of erl_tar as hex_erl_tar, and Hex and rebar3 ship hex_core with prefixed module names (mix_hex_erl_tar and r3_hex_erl_tar). These copies contain the same code and do not call stdlib\u0027s erl_tar, so they are affected on any OTP version. OTP 28 is not affected, but an application running on OTP 28 is affected if it extracts archives through an affected version of hex_core, Hex or rebar3.\n\nThis issue affects OTP from OTP\u00a029.0 before OTP\u00a029.1.2, corresponding to stdlib from 8.0 before 8.1.1, and rebar3 from 3.27.1 onward, and hex from 2.4.2 before 2.5.3; hex_core: from 0.14.0 before 0.20.1."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eAn attacker who can get an application to extract a tar archive to disk keeps the extracting process and one scheduler busy forever. Each further archive occupies another scheduler, until the node stops responding.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "An attacker who can get an application to extract a tar archive to disk keeps the extracting process and one scheduler busy forever. Each further archive occupies another scheduler, until the node stops responding."
                    }
                  ],
                  "value": "An attacker who can get an application to extract a tar archive to disk keeps the extracting process and one scheduler busy forever. Each further archive occupies another scheduler, until the node stops responding."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "LOCAL",
                "baseScore": 5.9,
                "baseSeverity": "MEDIUM",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "NONE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:L/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-835",
                  "description": "CWE-835 Loop with Unreachable Exit Condition (\u0027Infinite Loop\u0027)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-14T21:46:30.112Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/erlang/otp/security/advisories/GHSA-phm5-m6cj-5382"
            },
            {
              "name": "EEF CNA record for CVE-2026-96596",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-96596.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-96596",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-96596"
            },
            {
              "name": "Erlang/OTP version ordering",
              "tags": [
                "x_version-scheme"
              ],
              "url": "https://www.erlang.org/doc/system/versions.html#order-of-versions"
            },
            {
              "name": "Introducing commit fbf2c71 in erlang/otp",
              "tags": [
                "related"
              ],
              "url": "https://github.com/erlang/otp/commit/fbf2c7194f6fce4b7b66dc0bcaa4f6b4b85e088f"
            },
            {
              "name": "Fix commit 3086307 in erlang/otp",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/erlang/otp/commit/3086307f311b78b38644a7787a3aca6a3f95a9d5"
            },
            {
              "name": "Introducing commit 23dbdb5 in erlang/rebar3",
              "tags": [
                "related"
              ],
              "url": "https://github.com/erlang/rebar3/commit/23dbdb5d1f87f56902aef296c88a20049cd0c6e4"
            },
            {
              "name": "Introducing commit 13bb9fb in hexpm/hex_core",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/13bb9fbba418a406af614790b8d5cd458259ee70"
            },
            {
              "name": "Fix commit a2ece68 in hexpm/hex_core",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/a2ece683e6e88a3ec95ad20b09aca426e08b372e"
            },
            {
              "name": "Introducing commit 5543a19 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/5543a1919c709d8eb2b317f62aad76ca1eed375c"
            },
            {
              "name": "Fix commit 8e10671 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/8e1067131a13949eff30623f31648a945ffd5418"
            },
            {
              "name": "Fix commit 7847c23 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/7847c23d09ab52113614c3718e1e7d368743da5d"
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "erl_tar:extract/2 loops forever on a GNU sparse member with a trailing hole",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003ePass \u003ccode\u003e{chunks, N}\u003c/code\u003e together with \u003ccode\u003e{max_size, N}\u003c/code\u003e, with the same value N, to \u003ccode\u003eerl_tar:extract/2\u003c/code\u003e. Extraction then rejects any member larger than N, and reads each remaining member in one call, so the loop cannot occur.\u003c/p\u003e\n\u003cp\u003eAlternatively, extract with the \u003ccode\u003ememory\u003c/code\u003e option and write the returned files to disk in the application.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Pass `{chunks, N}` together with `{max_size, N}`, with the same value N, to `erl_tar:extract/2`. Extraction then rejects any member larger than N, and reads each remaining member in one call, so the loop cannot occur.\n\nAlternatively, extract with the `memory` option and write the returned files to disk in the application."
                }
              ],
              "value": "Pass {chunks, N} together with {max_size, N}, with the same value N, to erl_tar:extract/2. Extraction then rejects any member larger than N, and reads each remaining member in one call, so the loop cannot occur.\n\nAlternatively, extract with the memory option and write the returned files to disk in the application."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eBuild a 2048-byte tar that holds one GNU sparse member (typeflag \u003ccode\u003eS\u003c/code\u003e). Give it a stored size of 4 bytes, one sparse map entry of 4 bytes at offset 0, and a real size of 1048576 bytes. Follow the 512-byte header with a 512-byte block that starts with the 4 data bytes, then 1024 zero bytes.\u003c/li\u003e\n\u003cli\u003eIn a separate process, call \u003ccode\u003eerl_tar:extract({binary, Tar}, [{cwd, Dir}])\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eThe call does not return. After 5 seconds the process has used more than 10^9 reductions. On OTP 28 the same call returns \u003ccode\u003eok\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Build a 2048-byte tar that holds one GNU sparse member (typeflag `S`). Give it a stored size of 4 bytes, one sparse map entry of 4 bytes at offset 0, and a real size of 1048576 bytes. Follow the 512-byte header with a 512-byte block that starts with the 4 data bytes, then 1024 zero bytes.\n2. In a separate process, call `erl_tar:extract({binary, Tar}, [{cwd, Dir}])`.\n3. The call does not return. After 5 seconds the process has used more than 10^9 reductions. On OTP 28 the same call returns `ok`."
                }
              ],
              "value": "* Build a 2048-byte tar that holds one GNU sparse member (typeflag S). Give it a stored size of 4 bytes, one sparse map entry of 4 bytes at offset 0, and a real size of 1048576 bytes. Follow the 512-byte header with a 512-byte block that starts with the 4 data bytes, then 1024 zero bytes.\n* In a separate process, call erl_tar:extract({binary, Tar}, [{cwd, Dir}]).\n* The call does not return. After 5 seconds the process has used more than 10^9 reductions. On OTP 28 the same call returns ok."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003e\u003cstrong\u003e1. Chunked extraction.\u003c/strong\u003e \u003ccode\u003eerl_tar:extract/2\u003c/code\u003e writes each member to disk through \u003ccode\u003estream_to_file_loop/3\u003c/code\u003e. This function calls \u003ccode\u003edo_read(Reader, ChunkSize)\u003c/code\u003e until the \u003ccode\u003enum_bytes\u003c/code\u003e field of the reader is 0. The default chunk size is 65536 bytes.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e2. Clause order in \u003ccode\u003edo_sparse_read/3\u003c/code\u003e.\u003c/strong\u003e For a sparse member, \u003ccode\u003edo_read/2\u003c/code\u003e calls \u003ccode\u003edo_sparse_read/3\u003c/code\u003e. The clause for a trailing hole matches when \u003ccode\u003esparse_map\u003c/code\u003e is \u003ccode\u003e[]\u003c/code\u003e and \u003ccode\u003ePos \u0026lt; Size\u003c/code\u003e. It comes before the clause that returns when \u003ccode\u003eLen\u003c/code\u003e is 0.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e3. Unbounded recursion.\u003c/strong\u003e The member is a GNU sparse member (typeflag \u003ccode\u003eS\u003c/code\u003e) whose real size is larger than one chunk and whose sparse map ends before the real size. After the data fragments, the trailing-hole clause reads the rest of the chunk and recurses with \u003ccode\u003eLen = 0\u003c/code\u003e. The same clause matches again, and \u003ccode\u003eread_sparse_hole/3\u003c/code\u003e returns an empty binary and leaves \u003ccode\u003ePos\u003c/code\u003e unchanged. The zero-length clause is never reached, so the call never returns.\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e4. No mitigation from \u003ccode\u003emax_size\u003c/code\u003e.\u003c/strong\u003e For a sparse member, \u003ccode\u003e{max_size, N}\u003c/code\u003e is checked against the real size from the header. It stops the loop only when N is below that size. \u003ccode\u003eerl_tar:table/2\u003c/code\u003e lists the member as \u003ccode\u003eregular\u003c/code\u003e, so a caller cannot skip sparse members by type.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "**1. Chunked extraction.** `erl_tar:extract/2` writes each member to disk through `stream_to_file_loop/3`. This function calls `do_read(Reader, ChunkSize)` until the `num_bytes` field of the reader is 0. The default chunk size is 65536 bytes.\n\n**2. Clause order in `do_sparse_read/3`.** For a sparse member, `do_read/2` calls `do_sparse_read/3`. The clause for a trailing hole matches when `sparse_map` is `[]` and `Pos \u003c Size`. It comes before the clause that returns when `Len` is 0.\n\n**3. Unbounded recursion.** The member is a GNU sparse member (typeflag `S`) whose real size is larger than one chunk and whose sparse map ends before the real size. After the data fragments, the trailing-hole clause reads the rest of the chunk and recurses with `Len = 0`. The same clause matches again, and `read_sparse_hole/3` returns an empty binary and leaves `Pos` unchanged. The zero-length clause is never reached, so the call never returns.\n\n**4. No mitigation from `max_size`.** For a sparse member, `{max_size, N}` is checked against the real size from the header. It stops the loop only when N is below that size. `erl_tar:table/2` lists the member as `regular`, so a caller cannot skip sparse members by type."
                }
              ],
              "value": "1. Chunked extraction. erl_tar:extract/2 writes each member to disk through stream_to_file_loop/3. This function calls do_read(Reader, ChunkSize) until the num_bytes field of the reader is 0. The default chunk size is 65536 bytes.\n\n2. Clause order in do_sparse_read/3. For a sparse member, do_read/2 calls do_sparse_read/3. The clause for a trailing hole matches when sparse_map is [] and Pos \u003c Size. It comes before the clause that returns when Len is 0.\n\n3. Unbounded recursion. The member is a GNU sparse member (typeflag S) whose real size is larger than one chunk and whose sparse map ends before the real size. After the data fragments, the trailing-hole clause reads the rest of the chunk and recurses with Len = 0. The same clause matches again, and read_sparse_hole/3 returns an empty binary and leaves Pos unchanged. The zero-length clause is never reached, so the call never returns.\n\n4. No mitigation from max_size. For a sparse member, {max_size, N} is checked against the real size from the header. It stops the loop only when N is below that size. erl_tar:table/2 lists the member as regular, so a caller cannot skip sparse members by type."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-96596",
        "datePublished": "2026-10-14T16:56:18.530Z",
        "dateReserved": "2026-09-27T12:00:01.540Z",
        "dateUpdated": "2026-10-14T21:46:30.112Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-105274 (GCVE-0-2026-105274)

    Vulnerability from cvelistv5 – Published: 2026-10-12 16:43 – Updated: 2026-10-15 18:05
    VLAI
    Title
    hex_core decompresses registry and Erlang term API responses without size limits
    Summary
    Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core's API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (mix_hex_repo, mix_hex_api) and rebar3 (r3_hex_repo, r3_hex_api). hex_repo:get_names/1, hex_repo:get_versions/1, hex_repo:get_package/2 and hex_repo:get_policy/2 decompress the registry response with zlib:gunzip/1 and decode the signed envelope before verifying its signature. A mirror doesn't have the repository's private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it. hex_api decodes responses with the application/vnd.hex+erlang content type through hex_safe_binary_to_term:safe_binary_to_term/1, which calls binary_to_term(Binary, [safe]). The safe option prevents atom creation, but it accepts compressed terms and doesn't limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the safe option and that check without bounding the decoded size. This issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0.
    SSVC
    Exploitation: none Automatable: no Technical Impact: partial
    CISA Coordinator · CISA-ADP (v2.0.3)
    Decision recorded 2026-10-15 17:51 UTC
    CWE
    • CWE-409 - Improper Handling of Highly Compressed Data (Data Amplification)
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    erlang rebar3 Affected: 3.9.1 , < 3.27.3 (semver)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 209c02ec57c2cc3207ee0174c3af3675b8dc8f79 , < 360838a22f5b3a88c0358207f2923059bcbb3afb (git)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 0.1.0 , < 0.20.0 (semver)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: fbb6d9de472e5edb8d6fb6b32a91cb266137892e , < ebe25d110717f6a3addba5232cd4a7dc1c76b628 (git)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 2.1.0 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 671f695ac548ed01f5828c2a739ecaa942b21007 , < d8b60eee97abb119d525306f048969a217d793a5 (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Date Public
    2026-10-12 16:43
    Show details on NVD website

    {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-105274",
                    "options": [
                      {
                        "Exploitation": "none"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "partial"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-10-15T17:51:41.556015Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-10-15T18:05:12.446Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_repo",
                "r3_hex_api"
              ],
              "packageName": "rebar3",
              "packageURL": "pkg:otp/rebar3?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Frebar3\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Frebar3.git",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_repo.erl",
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_repo:get_names/1"
                },
                {
                  "name": "r3_hex_repo:get_versions/1"
                },
                {
                  "name": "r3_hex_repo:get_package/2"
                },
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "3.27.3",
                  "status": "affected",
                  "version": "3.9.1",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_repo",
                "r3_hex_api"
              ],
              "packageName": "erlang/rebar3",
              "packageURL": "pkg:github/erlang/rebar3",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_repo.erl",
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_repo:get_names/1"
                },
                {
                  "name": "r3_hex_repo:get_versions/1"
                },
                {
                  "name": "r3_hex_repo:get_package/2"
                },
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "360838a22f5b3a88c0358207f2923059bcbb3afb",
                  "status": "affected",
                  "version": "209c02ec57c2cc3207ee0174c3af3675b8dc8f79",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_repo",
                "hex_api",
                "hex_safe_binary_to_term"
              ],
              "packageName": "hex_core",
              "packageURL": "pkg:hex/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_repo.erl",
                "src/hex_api.erl",
                "src/hex_safe_binary_to_term.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_repo:get_names/1"
                },
                {
                  "name": "hex_repo:get_versions/1"
                },
                {
                  "name": "hex_repo:get_package/2"
                },
                {
                  "name": "hex_repo:get_policy/2"
                },
                {
                  "name": "hex_api:request/4"
                },
                {
                  "name": "hex_safe_binary_to_term:safe_binary_to_term/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "0.20.0",
                  "status": "affected",
                  "version": "0.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_repo",
                "hex_api",
                "hex_safe_binary_to_term"
              ],
              "packageName": "hexpm/hex_core",
              "packageURL": "pkg:github/hexpm/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_repo.erl",
                "src/hex_api.erl",
                "src/hex_safe_binary_to_term.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_repo:get_names/1"
                },
                {
                  "name": "hex_repo:get_versions/1"
                },
                {
                  "name": "hex_repo:get_package/2"
                },
                {
                  "name": "hex_repo:get_policy/2"
                },
                {
                  "name": "hex_api:request/4"
                },
                {
                  "name": "hex_safe_binary_to_term:safe_binary_to_term/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "ebe25d110717f6a3addba5232cd4a7dc1c76b628",
                  "status": "affected",
                  "version": "fbb6d9de472e5edb8d6fb6b32a91cb266137892e",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_repo",
                "mix_hex_api"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_repo.erl",
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_repo:get_names/1"
                },
                {
                  "name": "mix_hex_repo:get_versions/1"
                },
                {
                  "name": "mix_hex_repo:get_package/2"
                },
                {
                  "name": "mix_hex_repo:get_policy/2"
                },
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "2.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_repo",
                "mix_hex_api"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_repo.erl",
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_repo:get_names/1"
                },
                {
                  "name": "mix_hex_repo:get_versions/1"
                },
                {
                  "name": "mix_hex_repo:get_package/2"
                },
                {
                  "name": "mix_hex_repo:get_policy/2"
                },
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "d8b60eee97abb119d525306f048969a217d793a5",
                  "status": "affected",
                  "version": "671f695ac548ed01f5828c2a739ecaa942b21007",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eRegistry decoding is affected when a repository\u0027s URL points at a mirror or another server the user doesn\u0027t trust with the availability of their builds, for example Hex\u0027s \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e and rebar3\u0027s \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e. API decoding is affected when the API URL points at such a server or an attacker can alter API responses. Requests to repo.hex.pm and hex.pm over verified HTTPS aren\u0027t affected.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Registry decoding is affected when a repository\u0027s URL points at a mirror or another server the user doesn\u0027t trust with the availability of their builds, for example Hex\u0027s `HEX_MIRROR_URL` or `mirror_url` and rebar3\u0027s `HEX_MIRROR_URL`. API decoding is affected when the API URL points at such a server or an attacker can alter API responses. Requests to repo.hex.pm and hex.pm over verified HTTPS aren\u0027t affected."
                }
              ],
              "value": "Registry decoding is affected when a repository\u0027s URL points at a mirror or another server the user doesn\u0027t trust with the availability of their builds, for example Hex\u0027s HEX_MIRROR_URL or mirror_url and rebar3\u0027s HEX_MIRROR_URL. API decoding is affected when the API URL points at such a server or an attacker can alter API responses. Requests to repo.hex.pm and hex.pm over verified HTTPS aren\u0027t affected."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "3.27.3",
                      "versionStartIncluding": "3.9.1",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.20.0",
                      "versionStartIncluding": "0.1.0",
                      "vulnerable": true
                    },
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "2.1.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:01:00.000Z",
          "datePublic": "2026-10-12T16:43:59.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core\u0027s API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (\u003ccode\u003emix_hex_repo\u003c/code\u003e, \u003ccode\u003emix_hex_api\u003c/code\u003e) and rebar3 (\u003ccode\u003er3_hex_repo\u003c/code\u003e, \u003ccode\u003er3_hex_api\u003c/code\u003e).\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehex_repo:get_names/1\u003c/code\u003e, \u003ccode\u003ehex_repo:get_versions/1\u003c/code\u003e, \u003ccode\u003ehex_repo:get_package/2\u003c/code\u003e and \u003ccode\u003ehex_repo:get_policy/2\u003c/code\u003e decompress the registry response with \u003ccode\u003ezlib:gunzip/1\u003c/code\u003e and decode the signed envelope before verifying its signature. A mirror doesn\u0027t have the repository\u0027s private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ehex_api\u003c/code\u003e decodes responses with the \u003ccode\u003eapplication/vnd.hex+erlang\u003c/code\u003e content type through \u003ccode\u003ehex_safe_binary_to_term:safe_binary_to_term/1\u003c/code\u003e, which calls \u003ccode\u003ebinary_to_term(Binary, [safe])\u003c/code\u003e. The \u003ccode\u003esafe\u003c/code\u003e option prevents atom creation, but it accepts compressed terms and doesn\u0027t limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the \u003ccode\u003esafe\u003c/code\u003e option and that check without bounding the decoded size.\u003c/p\u003e\n\u003cp\u003eThis issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core\u0027s API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (`mix_hex_repo`, `mix_hex_api`) and rebar3 (`r3_hex_repo`, `r3_hex_api`).\n\n`hex_repo:get_names/1`, `hex_repo:get_versions/1`, `hex_repo:get_package/2` and `hex_repo:get_policy/2` decompress the registry response with `zlib:gunzip/1` and decode the signed envelope before verifying its signature. A mirror doesn\u0027t have the repository\u0027s private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it.\n\n`hex_api` decodes responses with the `application/vnd.hex+erlang` content type through `hex_safe_binary_to_term:safe_binary_to_term/1`, which calls `binary_to_term(Binary, [safe])`. The `safe` option prevents atom creation, but it accepts compressed terms and doesn\u0027t limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the `safe` option and that check without bounding the decoded size.\n\nThis issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0."
                }
              ],
              "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex_core allows an untrusted repository mirror, or a server answering hex_core\u0027s API requests, to exhaust the memory of the Erlang VM running hex_core. The same code is vendored in Hex (mix_hex_repo, mix_hex_api) and rebar3 (r3_hex_repo, r3_hex_api).\n\nhex_repo:get_names/1, hex_repo:get_versions/1, hex_repo:get_package/2 and hex_repo:get_policy/2 decompress the registry response with zlib:gunzip/1 and decode the signed envelope before verifying its signature. A mirror doesn\u0027t have the repository\u0027s private key, but it chooses the compressed bytes, so a small response decompresses into an envelope of any size before the signature check rejects it.\n\nhex_api decodes responses with the application/vnd.hex+erlang content type through hex_safe_binary_to_term:safe_binary_to_term/1, which calls binary_to_term(Binary, [safe]). The safe option prevents atom creation, but it accepts compressed terms and doesn\u0027t limit the size of the decoded term, and the check that rejects functions and ports runs after the term has been built. The fix for CVE-2026-21619 added the safe option and that check without bounding the decoded size.\n\nThis issue affects rebar3: from 3.9.1 before 3.27.3; hex: from 2.1.0 before 2.5.2; hex_core: from 0.1.0 before 0.20.0."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA mirror can make every registry fetch allocate memory far beyond the size of its response: in a test against Hex main 851b938, which vendors this code, a 65 KB registry response decompressed into a 64 MiB envelope before the signature check failed. The API server, or an attacker who can alter its responses, can do the same with API responses: 8 KB of compressed Erlang term format decoded into a list of 4.2 million elements. Large enough responses stop the Erlang VM, which fails the build tool command or the program using hex_core. No package code has to run.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A mirror can make every registry fetch allocate memory far beyond the size of its response: in a test against Hex main 851b938, which vendors this code, a 65 KB registry response decompressed into a 64 MiB envelope before the signature check failed. The API server, or an attacker who can alter its responses, can do the same with API responses: 8 KB of compressed Erlang term format decoded into a list of 4.2 million elements. Large enough responses stop the Erlang VM, which fails the build tool command or the program using hex_core. No package code has to run."
                    }
                  ],
                  "value": "A mirror can make every registry fetch allocate memory far beyond the size of its response: in a test against Hex main 851b938, which vendors this code, a 65 KB registry response decompressed into a 64 MiB envelope before the signature check failed. The API server, or an attacker who can alter its responses, can do the same with API responses: 8 KB of compressed Erlang term format decoded into a list of 4.2 million elements. Large enough responses stop the Erlang VM, which fails the build tool command or the program using hex_core. No package code has to run."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2.1,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "LOW",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-409",
                  "description": "CWE-409 Improper Handling of Highly Compressed Data (Data Amplification)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T18:16:57.155Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq"
            },
            {
              "name": "EEF CNA record for CVE-2026-105274",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-105274.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-105274",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-105274"
            },
            {
              "name": "Introducing commit 209c02e in erlang/rebar3",
              "tags": [
                "related"
              ],
              "url": "https://github.com/erlang/rebar3/commit/209c02ec57c2cc3207ee0174c3af3675b8dc8f79"
            },
            {
              "name": "Fix commit 360838a in erlang/rebar3",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/erlang/rebar3/commit/360838a22f5b3a88c0358207f2923059bcbb3afb"
            },
            {
              "name": "Introducing commit fbb6d9d in hexpm/hex_core",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/fbb6d9de472e5edb8d6fb6b32a91cb266137892e"
            },
            {
              "name": "Fix commit ebe25d1 in hexpm/hex_core",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/ebe25d110717f6a3addba5232cd4a7dc1c76b628"
            },
            {
              "name": "Introducing commit 671f695 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/671f695ac548ed01f5828c2a739ecaa942b21007"
            },
            {
              "name": "Fix commit d8b60ee in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/d8b60eee97abb119d525306f048969a217d793a5"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade hex_core to 0.20.0 or later. Registry resources larger than 16 MiB after decompression are rejected with \u003ccode\u003e{too_big_uncompressed, MaxSize}\u003c/code\u003e, configurable with \u003ccode\u003eregistry_max_uncompressed_size\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eUpgrade Hex to 2.5.2 or later, which vendors hex_core 0.20.0. No rebar3 release vendors hex_core 0.20.0 yet.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade hex_core to 0.20.0 or later. Registry resources larger than 16 MiB after decompression are rejected with `{too_big_uncompressed, MaxSize}`, configurable with `registry_max_uncompressed_size`.\n\nUpgrade Hex to 2.5.2 or later, which vendors hex_core 0.20.0. No rebar3 release vendors hex_core 0.20.0 yet."
                }
              ],
              "value": "Upgrade hex_core to 0.20.0 or later. Registry resources larger than 16 MiB after decompression are rejected with {too_big_uncompressed, MaxSize}, configurable with registry_max_uncompressed_size.\n\nUpgrade Hex to 2.5.2 or later, which vendors hex_core 0.20.0. No rebar3 release vendors hex_core 0.20.0 yet."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "hex_core decompresses registry and Erlang term API responses without size limits",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003ePoint repository URLs at repo.hex.pm or a mirror you operate, and the API URL at hex.pm.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Point repository URLs at repo.hex.pm or a mirror you operate, and the API URL at hex.pm."
                }
              ],
              "value": "Point repository URLs at repo.hex.pm or a mirror you operate, and the API URL at hex.pm."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003ePoint a repository at a loopback mirror (in Hex, \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e) that answers \u003ccode\u003e/packages/probe\u003c/code\u003e with a 65,268-byte gzip stream decompressing to a 67,108,872-byte signed envelope with a 64 MiB payload and a one-byte signature.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.Repo.get_package(\"hexpm\", \"probe\", nil)\u003c/code\u003e, which calls the vendored \u003ccode\u003ehex_repo:get_package/2\u003c/code\u003e, returns \u003ccode\u003e{:error, :bad_signature}\u003c/code\u003e after allocating the envelope. Peak RSS was 234 MiB, against 96 MiB for a 1,030-byte invalid envelope.\u003c/li\u003e\n\u003cli\u003eAnswer an API request with \u003ccode\u003econtent-type: application/vnd.hex+erlang\u003c/code\u003e and 8,178 bytes of compressed Erlang term format encoding a list of 4,194,304 elements. \u003ccode\u003emix_hex_api:get/2\u003c/code\u003e accepts the decoded term, and BEAM memory rises from 58 MiB to 272 MiB.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Point a repository at a loopback mirror (in Hex, `HEX_MIRROR_URL`) that answers `/packages/probe` with a 65,268-byte gzip stream decompressing to a 67,108,872-byte signed envelope with a 64 MiB payload and a one-byte signature.\n2. `Hex.Repo.get_package(\"hexpm\", \"probe\", nil)`, which calls the vendored `hex_repo:get_package/2`, returns `{:error, :bad_signature}` after allocating the envelope. Peak RSS was 234 MiB, against 96 MiB for a 1,030-byte invalid envelope.\n3. Answer an API request with `content-type: application/vnd.hex+erlang` and 8,178 bytes of compressed Erlang term format encoding a list of 4,194,304 elements. `mix_hex_api:get/2` accepts the decoded term, and BEAM memory rises from 58 MiB to 272 MiB."
                }
              ],
              "value": "* Point a repository at a loopback mirror (in Hex, HEX_MIRROR_URL) that answers /packages/probe with a 65,268-byte gzip stream decompressing to a 67,108,872-byte signed envelope with a 64 MiB payload and a one-byte signature.\n* Hex.Repo.get_package(\"hexpm\", \"probe\", nil), which calls the vendored hex_repo:get_package/2, returns {:error, :bad_signature} after allocating the envelope. Peak RSS was 234 MiB, against 96 MiB for a 1,030-byte invalid envelope.\n* Answer an API request with content-type: application/vnd.hex+erlang and 8,178 bytes of compressed Erlang term format encoding a list of 4,194,304 elements. mix_hex_api:get/2 accepts the decoded term, and BEAM memory rises from 58 MiB to 272 MiB."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003ehex_repo:get_protobuf/3\u003c/code\u003e, used by \u003ccode\u003eget_names/1\u003c/code\u003e, \u003ccode\u003eget_versions/1\u003c/code\u003e, \u003ccode\u003eget_package/2\u003c/code\u003e and \u003ccode\u003eget_policy/2\u003c/code\u003e, calls \u003ccode\u003ezlib:gunzip/1\u003c/code\u003e on the whole response body with no output limit.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehex_repo:decode/4\u003c/code\u003e then calls \u003ccode\u003ehex_registry:decode_and_verify_signed/2\u003c/code\u003e, which decodes the protobuf envelope, copying its payload and signature, before checking the signature.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003ehex_api:request/4\u003c/code\u003e passes every response whose content type contains \u003ccode\u003eapplication/vnd.hex+erlang\u003c/code\u003e to \u003ccode\u003ehex_safe_binary_to_term:safe_binary_to_term/1\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003esafe_binary_to_term/1\u003c/code\u003e calls \u003ccode\u003ebinary_to_term(Binary, [safe])\u003c/code\u003e, which decompresses compressed terms and builds the whole term, and only then walks it to reject functions and ports.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `hex_repo:get_protobuf/3`, used by `get_names/1`, `get_versions/1`, `get_package/2` and `get_policy/2`, calls `zlib:gunzip/1` on the whole response body with no output limit.\n2. `hex_repo:decode/4` then calls `hex_registry:decode_and_verify_signed/2`, which decodes the protobuf envelope, copying its payload and signature, before checking the signature.\n3. `hex_api:request/4` passes every response whose content type contains `application/vnd.hex+erlang` to `hex_safe_binary_to_term:safe_binary_to_term/1`.\n4. `safe_binary_to_term/1` calls `binary_to_term(Binary, [safe])`, which decompresses compressed terms and builds the whole term, and only then walks it to reject functions and ports."
                }
              ],
              "value": "* hex_repo:get_protobuf/3, used by get_names/1, get_versions/1, get_package/2 and get_policy/2, calls zlib:gunzip/1 on the whole response body with no output limit.\n* hex_repo:decode/4 then calls hex_registry:decode_and_verify_signed/2, which decodes the protobuf envelope, copying its payload and signature, before checking the signature.\n* hex_api:request/4 passes every response whose content type contains application/vnd.hex+erlang to hex_safe_binary_to_term:safe_binary_to_term/1.\n* safe_binary_to_term/1 calls binary_to_term(Binary, [safe]), which decompresses compressed terms and builds the whole term, and only then walks it to reject functions and ports."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-105274",
        "datePublished": "2026-10-12T16:43:58.730Z",
        "dateReserved": "2026-10-10T13:00:02.355Z",
        "dateUpdated": "2026-10-15T18:05:12.446Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-81856 (GCVE-0-2026-81856)

    Vulnerability from cvelistv5 – Published: 2026-10-12 15:46 – Updated: 2026-10-12 15:46
    VLAI
    Title
    Terminal escape sequence injection in Hex via unneutralized server-supplied output
    Summary
    Improper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks. Hex prints strings supplied by the package repository and the documentation search service straight to the terminal through Hex.Shell.info/1 and Hex.Shell.error/1, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in mix hex.info, search results in mix hex.package search and mix hex.search, owner and organization listings, publish and sponsor URLs, the authenticated username in mix hex.user, policy identities in mix hex.policy, and API error bodies rendered by Hex.Utils.print_error_result/1. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package. This issue affects hex: from 0.0.1 before 2.5.2.
    CWE
    • CWE-150 - Improper Neutralization of Escape, Meta, or Control Sequences
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.0.1 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 211303e3f68f5d3ce06450c1ff1a7a770a9ab236 , < dd3305ddf0032f6d0b468fd40dbbc3072bfcb8b8 (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Search\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.search.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Search\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.0.1",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Search\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.search.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Search\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "dd3305ddf0032f6d0b468fd40dbbc3072bfcb8b8",
                  "status": "affected",
                  "version": "211303e3f68f5d3ce06450c1ff1a7a770a9ab236",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eReachable only when a developer runs an affected Mix task in a terminal emulator that interprets ANSI escape sequences, and the printed content originates from an attacker-published package or a hostile repository server.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Reachable only when a developer runs an affected Mix task in a terminal emulator that interprets ANSI escape sequences, and the printed content originates from an attacker-published package or a hostile repository server."
                }
              ],
              "value": "Reachable only when a developer runs an affected Mix task in a terminal emulator that interprets ANSI escape sequences, and the printed content originates from an attacker-published package or a hostile repository server."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.0.1",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "reporter",
              "value": "Zach Daniel"
            },
            {
              "lang": "en",
              "type": "remediation reviewer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Jonatan M\u00e4nnchen"
            },
            {
              "lang": "en",
              "type": "coordinator",
              "value": "Jonatan M\u00e4nnchen"
            }
          ],
          "dateAssigned": "2026-09-09T16:47:17.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks.\u003c/p\u003e\n\u003cp\u003eHex prints strings supplied by the package repository and the documentation search service straight to the terminal through \u003ccode\u003eHex.Shell.info/1\u003c/code\u003e and \u003ccode\u003eHex.Shell.error/1\u003c/code\u003e, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in \u003ccode\u003emix hex.info\u003c/code\u003e, search results in \u003ccode\u003emix hex.package search\u003c/code\u003e and \u003ccode\u003emix hex.search\u003c/code\u003e, owner and organization listings, publish and sponsor URLs, the authenticated username in \u003ccode\u003emix hex.user\u003c/code\u003e, policy identities in \u003ccode\u003emix hex.policy\u003c/code\u003e, and API error bodies rendered by \u003ccode\u003eHex.Utils.print_error_result/1\u003c/code\u003e. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.0.1 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks.\n\nHex prints strings supplied by the package repository and the documentation search service straight to the terminal through `Hex.Shell.info/1` and `Hex.Shell.error/1`, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in `mix hex.info`, search results in `mix hex.package search` and `mix hex.search`, owner and organization listings, publish and sponsor URLs, the authenticated username in `mix hex.user`, policy identities in `mix hex.policy`, and API error bodies rendered by `Hex.Utils.print_error_result/1`. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package.\n\nThis issue affects hex: from 0.0.1 before 2.5.2."
                }
              ],
              "value": "Improper Neutralization of Escape, Meta, or Control Sequences vulnerability in hexpm hex allows a malicious package publisher or a hostile repository server to inject terminal control sequences into the output of Mix tasks.\n\nHex prints strings supplied by the package repository and the documentation search service straight to the terminal through Hex.Shell.info/1 and Hex.Shell.error/1, neutralizing no control characters. Affected sinks span package metadata and configuration snippets in mix hex.info, search results in mix hex.package search and mix hex.search, owner and organization listings, publish and sponsor URLs, the authenticated username in mix hex.user, policy identities in mix hex.policy, and API error bodies rendered by Hex.Utils.print_error_result/1. A malicious package can embed ANSI escape sequences (cursor movement, line erase, carriage returns, OSC 52 clipboard writes) or Unicode bidirectional overrides in any of those fields, so the bytes reach the terminal unchanged, forging displayed URLs, package descriptions and suggested commands, concealing real output, or writing to the clipboard. No authentication or privileged position is required; only publishing a package.\n\nThis issue affects hex: from 0.0.1 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-93",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA malicious package publisher can forge what a developer sees when running \u003ccode\u003emix hex.search\u003c/code\u003e, rewriting the displayed hexdocs URL or a suggested command, concealing real output, or writing attacker-chosen text to the clipboard through OSC 52. Any developer who runs a documentation search that surfaces the attacker\u0027s package is affected.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A malicious package publisher can forge what a developer sees when running `mix hex.search`, rewriting the displayed hexdocs URL or a suggested command, concealing real output, or writing attacker-chosen text to the clipboard through OSC 52. Any developer who runs a documentation search that surfaces the attacker\u0027s package is affected."
                    }
                  ],
                  "value": "A malicious package publisher can forge what a developer sees when running mix hex.search, rewriting the displayed hexdocs URL or a suggested command, concealing real output, or writing attacker-chosen text to the clipboard through OSC 52. Any developer who runs a documentation search that surfaces the attacker\u0027s package is affected."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2.3,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "PASSIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:P/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "LOW",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-150",
                  "description": "CWE-150 Improper Neutralization of Escape, Meta, or Control Sequences",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:46:12.146Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-fpmj-3cxg-p766"
            },
            {
              "name": "EEF CNA record for CVE-2026-81856",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-81856.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-81856",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-81856"
            },
            {
              "name": "Introducing commit 211303e in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/211303e3f68f5d3ce06450c1ff1a7a770a9ab236"
            },
            {
              "name": "Fix commit dd3305d in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/dd3305ddf0032f6d0b468fd40dbbc3072bfcb8b8"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. Hex then escapes terminal control characters in text from hex.pm and the registry before printing it, and rejects registry dependencies whose package or repository name isn\u0027t a valid name.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. Hex then escapes terminal control characters in text from hex.pm and the registry before printing it, and rejects registry dependencies whose package or repository name isn\u0027t a valid name."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. Hex then escapes terminal control characters in text from hex.pm and the registry before printing it, and rejects registry dependencies whose package or repository name isn\u0027t a valid name."
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "Terminal escape sequence injection in Hex via unneutralized server-supplied output"
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-81856",
        "datePublished": "2026-10-12T15:46:12.146Z",
        "dateReserved": "2026-08-31T00:45:02.431Z",
        "dateUpdated": "2026-10-12T15:46:12.146Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-96612 (GCVE-0-2026-96612)

    Vulnerability from cvelistv5 – Published: 2026-10-12 15:39 – Updated: 2026-10-12 15:39
    VLAI
    Title
    Path traversal in Hex via unvalidated dependency app names
    Summary
    Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal') vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project's deps directory and extract package files into it when a developer fetches dependencies. A package release's requirements carry an app label that names the dependency's OTP application. Hex takes this label from the repository's signed registry and uses it as the dependency's application name without validating it (Hex.RemoteConverger.deps/2, Hex.Mix.to_lock/1). Mix derives the dependency's checkout directory as deps/<app>, and Hex.SCM.update/1 runs File.rm_rf!/1 on that directory and unpacks the package into it. hex.pm only checks the label's length, so a publisher can set it to a value such as ../../target. When a project depends on such a release directly or transitively, mix deps.get or mix deps.update deletes the directory the label resolves to and writes the labelled package's files there. This happens before any dependency code is compiled. This issue affects hex: from 0.6.0 before 2.5.2.
    CWE
    • CWE-22 - Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.6.0 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 380f87054e1bc08ee13d2b5311bc01f98dad2fc6 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Mix\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/mix.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:deps/2"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:converge/2"
                },
                {
                  "name": "\u0027Elixir.Hex.Mix\u0027:to_lock/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:checkout/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.6.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Mix\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/mix.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:deps/2"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:converge/2"
                },
                {
                  "name": "\u0027Elixir.Hex.Mix\u0027:to_lock/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:checkout/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "1b3e2ae8f0dd7273a2c2625b9e50b6c67c8568fb",
                      "status": "unaffected"
                    },
                    {
                      "at": "72279a8e2004b32b20d8767ff010c117193dd02c",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "380f87054e1bc08ee13d2b5311bc01f98dad2fc6",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects projects whose dependency tree, directly or transitively, contains a package release whose registry metadata carries a crafted dependency \u003ccode\u003eapp\u003c/code\u003e label, when dependencies are fetched with \u003ccode\u003emix deps.get\u003c/code\u003e or \u003ccode\u003emix deps.update\u003c/code\u003e. Packages on hex.pm are affected while hex.pm accepts such labels; packages on self-hosted repositories are affected when the repository operator signs such metadata.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects projects whose dependency tree, directly or transitively, contains a package release whose registry metadata carries a crafted dependency `app` label, when dependencies are fetched with `mix deps.get` or `mix deps.update`. Packages on hex.pm are affected while hex.pm accepts such labels; packages on self-hosted repositories are affected when the repository operator signs such metadata."
                }
              ],
              "value": "Affects projects whose dependency tree, directly or transitively, contains a package release whose registry metadata carries a crafted dependency app label, when dependencies are fetched with mix deps.get or mix deps.update. Packages on hex.pm are affected while hex.pm accepts such labels; packages on self-hosted repositories are affected when the repository operator signs such metadata."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.6.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-07T22:03:18.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027) vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project\u0027s \u003ccode\u003edeps\u003c/code\u003e directory and extract package files into it when a developer fetches dependencies.\u003c/p\u003e\n\u003cp\u003eA package release\u0027s requirements carry an \u003ccode\u003eapp\u003c/code\u003e label that names the dependency\u0027s OTP application. Hex takes this label from the repository\u0027s signed registry and uses it as the dependency\u0027s application name without validating it (\u003ccode\u003eHex.RemoteConverger.deps/2\u003c/code\u003e, \u003ccode\u003eHex.Mix.to_lock/1\u003c/code\u003e). Mix derives the dependency\u0027s checkout directory as \u003ccode\u003edeps/\u0026lt;app\u0026gt;\u003c/code\u003e, and \u003ccode\u003eHex.SCM.update/1\u003c/code\u003e runs \u003ccode\u003eFile.rm_rf!/1\u003c/code\u003e on that directory and unpacks the package into it. hex.pm only checks the label\u0027s length, so a publisher can set it to a value such as \u003ccode\u003e../../target\u003c/code\u003e. When a project depends on such a release directly or transitively, \u003ccode\u003emix deps.get\u003c/code\u003e or \u003ccode\u003emix deps.update\u003c/code\u003e deletes the directory the label resolves to and writes the labelled package\u0027s files there. This happens before any dependency code is compiled.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.6.0 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027) vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project\u0027s `deps` directory and extract package files into it when a developer fetches dependencies.\n\nA package release\u0027s requirements carry an `app` label that names the dependency\u0027s OTP application. Hex takes this label from the repository\u0027s signed registry and uses it as the dependency\u0027s application name without validating it (`Hex.RemoteConverger.deps/2`, `Hex.Mix.to_lock/1`). Mix derives the dependency\u0027s checkout directory as `deps/\u003capp\u003e`, and `Hex.SCM.update/1` runs `File.rm_rf!/1` on that directory and unpacks the package into it. hex.pm only checks the label\u0027s length, so a publisher can set it to a value such as `../../target`. When a project depends on such a release directly or transitively, `mix deps.get` or `mix deps.update` deletes the directory the label resolves to and writes the labelled package\u0027s files there. This happens before any dependency code is compiled.\n\nThis issue affects hex: from 0.6.0 before 2.5.2."
                }
              ],
              "value": "Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027) vulnerability in hexpm hex allows a malicious package publisher to delete a directory outside the project\u0027s deps directory and extract package files into it when a developer fetches dependencies.\n\nA package release\u0027s requirements carry an app label that names the dependency\u0027s OTP application. Hex takes this label from the repository\u0027s signed registry and uses it as the dependency\u0027s application name without validating it (Hex.RemoteConverger.deps/2, Hex.Mix.to_lock/1). Mix derives the dependency\u0027s checkout directory as deps/\u003capp\u003e, and Hex.SCM.update/1 runs File.rm_rf!/1 on that directory and unpacks the package into it. hex.pm only checks the label\u0027s length, so a publisher can set it to a value such as ../../target. When a project depends on such a release directly or transitively, mix deps.get or mix deps.update deletes the directory the label resolves to and writes the labelled package\u0027s files there. This happens before any dependency code is compiled.\n\nThis issue affects hex: from 0.6.0 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-126",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA publisher of any package in a project\u0027s dependency tree can make \u003ccode\u003emix deps.get\u003c/code\u003e delete a directory that the developer\u0027s account can write and that \u003ccode\u003e..\u003c/code\u003e segments relative to \u003ccode\u003edeps\u003c/code\u003e reach, such as the project directory or its parent, and fill it with the labelled package\u0027s files. Writing attacker-chosen files into a directory whose contents are later run or loaded can lead to code execution without the developer compiling the dependency. Developers who fetch dependencies to review them before compiling, CI jobs and dependency update bots that only run \u003ccode\u003emix deps.get\u003c/code\u003e or \u003ccode\u003emix deps.update\u003c/code\u003e are affected.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A publisher of any package in a project\u0027s dependency tree can make `mix deps.get` delete a directory that the developer\u0027s account can write and that `..` segments relative to `deps` reach, such as the project directory or its parent, and fill it with the labelled package\u0027s files. Writing attacker-chosen files into a directory whose contents are later run or loaded can lead to code execution without the developer compiling the dependency. Developers who fetch dependencies to review them before compiling, CI jobs and dependency update bots that only run `mix deps.get` or `mix deps.update` are affected."
                    }
                  ],
                  "value": "A publisher of any package in a project\u0027s dependency tree can make mix deps.get delete a directory that the developer\u0027s account can write and that .. segments relative to deps reach, such as the project directory or its parent, and fill it with the labelled package\u0027s files. Writing attacker-chosen files into a directory whose contents are later run or loaded can lead to code execution without the developer compiling the dependency. Developers who fetch dependencies to review them before compiling, CI jobs and dependency update bots that only run mix deps.get or mix deps.update are affected."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 7.5,
                "baseSeverity": "HIGH",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-22",
                  "description": "CWE-22 Improper Limitation of a Pathname to a Restricted Directory (\u0027Path Traversal\u0027)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:39:49.862Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-2vjj-c5hr-6xc3"
            },
            {
              "name": "EEF CNA record for CVE-2026-96612",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-96612.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-96612",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-96612"
            },
            {
              "name": "Introducing commit 380f870 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/380f87054e1bc08ee13d2b5311bc01f98dad2fc6"
            },
            {
              "name": "Fix commit 1b3e2ae in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/1b3e2ae8f0dd7273a2c2625b9e50b6c67c8568fb"
            },
            {
              "name": "Fix commit 72279a8 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/72279a8e2004b32b20d8767ff010c117193dd02c"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. Hex then skips package releases that give a dependency an application name other than a letter followed by letters, digits, \u003ccode\u003e_\u003c/code\u003e and \u003ccode\u003e-\u003c/code\u003e, and warns about them. Resolution fails if no other release of the package fits the requirements.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. Hex then skips package releases that give a dependency an application name other than a letter followed by letters, digits, `_` and `-`, and warns about them. Resolution fails if no other release of the package fits the requirements."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. Hex then skips package releases that give a dependency an application name other than a letter followed by letters, digits, _ and -, and warns about them. Resolution fails if no other release of the package fits the requirements."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Path traversal in Hex via unvalidated dependency app names",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eBefore running \u003ccode\u003emix deps.get\u003c/code\u003e on a \u003ccode\u003emix.lock\u003c/code\u003e from an untrusted change, check that every key in \u003ccode\u003emix.lock\u003c/code\u003e is a plain application name without \u003ccode\u003e/\u003c/code\u003e, \u003ccode\u003e\\\u003c/code\u003e or \u003ccode\u003e..\u003c/code\u003e. There\u0027s no workaround for new dependency resolution with \u003ccode\u003emix deps.update\u003c/code\u003e or \u003ccode\u003emix deps.get\u003c/code\u003e without a lock entry.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Before running `mix deps.get` on a `mix.lock` from an untrusted change, check that every key in `mix.lock` is a plain application name without `/`, `\\` or `..`. There\u0027s no workaround for new dependency resolution with `mix deps.update` or `mix deps.get` without a lock entry."
                }
              ],
              "value": "Before running mix deps.get on a mix.lock from an untrusted change, check that every key in mix.lock is a plain application name without /, \\ or ... There\u0027s no workaround for new dependency resolution with mix deps.update or mix deps.get without a lock entry."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003ePublish package \u003ccode\u003ebeta\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003ePublish package \u003ccode\u003ealpha\u003c/code\u003e with a requirement on \u003ccode\u003ebeta\u003c/code\u003e whose \u003ccode\u003eapp\u003c/code\u003e is \u003ccode\u003e../../escape_marker\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eIn a project that depends on \u003ccode\u003ealpha\u003c/code\u003e, create \u003ccode\u003e../escape_marker/canary.txt\u003c/code\u003e next to the project directory.\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003emix deps.get\u003c/code\u003e. Hex prints \u003ccode\u003e* Updating ../../escape_marker (Hex package)\u003c/code\u003e, deletes \u003ccode\u003ecanary.txt\u003c/code\u003e and writes \u003ccode\u003ebeta\u003c/code\u003e\u0027s files into \u003ccode\u003e../escape_marker\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Publish package `beta`.\n2. Publish package `alpha` with a requirement on `beta` whose `app` is `../../escape_marker`.\n3. In a project that depends on `alpha`, create `../escape_marker/canary.txt` next to the project directory.\n4. Run `mix deps.get`. Hex prints `* Updating ../../escape_marker (Hex package)`, deletes `canary.txt` and writes `beta`\u0027s files into `../escape_marker`."
                }
              ],
              "value": "* Publish package beta.\n* Publish package alpha with a requirement on beta whose app is ../../escape_marker.\n* In a project that depends on alpha, create ../escape_marker/canary.txt next to the project directory.\n* Run mix deps.get. Hex prints * Updating ../../escape_marker (Hex package), deletes canary.txt and writes beta\u0027s files into ../escape_marker."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003ehex.pm stores each requirement\u0027s \u003ccode\u003eapp\u003c/code\u003e field with only a length check (255 codepoints) and copies it into the signed package registry resource when it differs from the dependency\u0027s package name.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.RemoteConverger.deps/2\u003c/code\u003e returns the dependency\u0027s children with \u003ccode\u003eString.to_atom/1\u003c/code\u003e of that label as the application name, and \u003ccode\u003eHex.Mix.to_lock/1\u003c/code\u003e writes it as the \u003ccode\u003emix.lock\u003c/code\u003e key.\u003c/li\u003e\n\u003cli\u003eMix computes the dependency destination as \u003ccode\u003ePath.join(Mix.Project.deps_path(), Atom.to_string(app))\u003c/code\u003e without validating the name.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.SCM.update/1\u003c/code\u003e calls \u003ccode\u003eFile.rm_rf!(dest)\u003c/code\u003e and then \u003ccode\u003eHex.Tar.unpack!(path, dest)\u003c/code\u003e, so a label containing \u003ccode\u003e..\u003c/code\u003e segments deletes and repopulates a directory outside \u003ccode\u003edeps\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eMix doesn\u0027t evaluate a Hex dependency\u0027s \u003ccode\u003emix.exs\u003c/code\u003e during \u003ccode\u003emix deps.get\u003c/code\u003e, so this is reachable before any package code runs.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. hex.pm stores each requirement\u0027s `app` field with only a length check (255 codepoints) and copies it into the signed package registry resource when it differs from the dependency\u0027s package name.\n2. `Hex.RemoteConverger.deps/2` returns the dependency\u0027s children with `String.to_atom/1` of that label as the application name, and `Hex.Mix.to_lock/1` writes it as the `mix.lock` key.\n3. Mix computes the dependency destination as `Path.join(Mix.Project.deps_path(), Atom.to_string(app))` without validating the name.\n4. `Hex.SCM.update/1` calls `File.rm_rf!(dest)` and then `Hex.Tar.unpack!(path, dest)`, so a label containing `..` segments deletes and repopulates a directory outside `deps`.\n5. Mix doesn\u0027t evaluate a Hex dependency\u0027s `mix.exs` during `mix deps.get`, so this is reachable before any package code runs."
                }
              ],
              "value": "* hex.pm stores each requirement\u0027s app field with only a length check (255 codepoints) and copies it into the signed package registry resource when it differs from the dependency\u0027s package name.\n* Hex.RemoteConverger.deps/2 returns the dependency\u0027s children with String.to_atom/1 of that label as the application name, and Hex.Mix.to_lock/1 writes it as the mix.lock key.\n* Mix computes the dependency destination as Path.join(Mix.Project.deps_path(), Atom.to_string(app)) without validating the name.\n* Hex.SCM.update/1 calls File.rm_rf!(dest) and then Hex.Tar.unpack!(path, dest), so a label containing .. segments deletes and repopulates a directory outside deps.\n* Mix doesn\u0027t evaluate a Hex dependency\u0027s mix.exs during mix deps.get, so this is reachable before any package code runs."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-96612",
        "datePublished": "2026-10-12T15:39:49.862Z",
        "dateReserved": "2026-10-01T09:00:02.103Z",
        "dateUpdated": "2026-10-12T15:39:49.862Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-105668 (GCVE-0-2026-105668)

    Vulnerability from cvelistv5 – Published: 2026-10-12 15:31 – Updated: 2026-10-12 15:31
    VLAI
    Title
    Hex release-age cooldown is lifted package-wide when the locked release is retired
    Summary
    Protection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner's account, to get a newly published release past the release-age cooldown. The cooldown (cooldown config, HEX_COOLDOWN) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in mix.lock is retired or has a security advisory, Hex.RemoteConverger.build_cooldown_bypass/3 and Hex.RemoteConverger.unsafe_lock_bypass/1 lift the cooldown for every version of that package and of every package the locked release depends on, so that mix deps.update can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next mix deps.update that unlocks the package selects the new release regardless of its age. Hex.Registry.Cooldown.versions/2 checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected. This issue affects hex: from 2.5.0 before 2.5.2.
    CWE
    • CWE-693 - Protection Mechanism Failure
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 2.5.0 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: b4e665d46be8a5f81e8cbbe4c3a67058a19cf133 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Registry.Cooldown\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/registry/cooldown.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:build_cooldown_bypass/3"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:unsafe_lock_bypass/1"
                },
                {
                  "name": "\u0027Elixir.Hex.Registry.Cooldown\u0027:versions/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "2.5.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027",
                "\u0027Elixir.Hex.Registry.Cooldown\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex",
                "lib/hex/registry/cooldown.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:build_cooldown_bypass/3"
                },
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:unsafe_lock_bypass/1"
                },
                {
                  "name": "\u0027Elixir.Hex.Registry.Cooldown\u0027:versions/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "eed2bdf85320ae9e244629511c03f5f3f8c5d0b5",
                      "status": "unaffected"
                    },
                    {
                      "at": "1b6fddfeadd98ed26a143f60356efade0494e2ae",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "b4e665d46be8a5f81e8cbbe4c3a67058a19cf133",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects projects that set the \u003ccode\u003ecooldown\u003c/code\u003e config or \u003ccode\u003eHEX_COOLDOWN\u003c/code\u003e and update dependencies with \u003ccode\u003emix deps.update\u003c/code\u003e, or otherwise unlock the package during resolution. Cooldowns enforced through an organization dependency policy aren\u0027t affected.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects projects that set the `cooldown` config or `HEX_COOLDOWN` and update dependencies with `mix deps.update`, or otherwise unlock the package during resolution. Cooldowns enforced through an organization dependency policy aren\u0027t affected."
                }
              ],
              "value": "Affects projects that set the cooldown config or HEX_COOLDOWN and update dependencies with mix deps.update, or otherwise unlock the package during resolution. Cooldowns enforced through an organization dependency policy aren\u0027t affected."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "2.5.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "coordinator",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:01:56.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eProtection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner\u0027s account, to get a newly published release past the release-age cooldown.\u003c/p\u003e\n\u003cp\u003eThe cooldown (\u003ccode\u003ecooldown\u003c/code\u003e config, \u003ccode\u003eHEX_COOLDOWN\u003c/code\u003e) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in \u003ccode\u003emix.lock\u003c/code\u003e is retired or has a security advisory, \u003ccode\u003eHex.RemoteConverger.build_cooldown_bypass/3\u003c/code\u003e and \u003ccode\u003eHex.RemoteConverger.unsafe_lock_bypass/1\u003c/code\u003e lift the cooldown for every version of that package and of every package the locked release depends on, so that \u003ccode\u003emix deps.update\u003c/code\u003e can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next \u003ccode\u003emix deps.update\u003c/code\u003e that unlocks the package selects the new release regardless of its age. \u003ccode\u003eHex.Registry.Cooldown.versions/2\u003c/code\u003e checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 2.5.0 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Protection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner\u0027s account, to get a newly published release past the release-age cooldown.\n\nThe cooldown (`cooldown` config, `HEX_COOLDOWN`) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in `mix.lock` is retired or has a security advisory, `Hex.RemoteConverger.build_cooldown_bypass/3` and `Hex.RemoteConverger.unsafe_lock_bypass/1` lift the cooldown for every version of that package and of every package the locked release depends on, so that `mix deps.update` can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next `mix deps.update` that unlocks the package selects the new release regardless of its age. `Hex.Registry.Cooldown.versions/2` checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected.\n\nThis issue affects hex: from 2.5.0 before 2.5.2."
                }
              ],
              "value": "Protection Mechanism Failure vulnerability in hexpm hex allows the owner of a package, or an attacker who has taken over the owner\u0027s account, to get a newly published release past the release-age cooldown.\n\nThe cooldown (cooldown config, HEX_COOLDOWN) withholds versions younger than the configured age during dependency resolution. When the release of a package locked in mix.lock is retired or has a security advisory, Hex.RemoteConverger.build_cooldown_bypass/3 and Hex.RemoteConverger.unsafe_lock_bypass/1 lift the cooldown for every version of that package and of every package the locked release depends on, so that mix deps.update can move off the unsafe release. Retiring a release needs the same package owner permission as publishing one. An attacker who publishes a malicious release can retire the currently locked release, and the next mix deps.update that unlocks the package selects the new release regardless of its age. Hex.Registry.Cooldown.versions/2 checks the bypass by package name alone, so the bypass also covers packages with the same name in other repositories. Cooldown configured through an organization dependency policy is not affected.\n\nThis issue affects hex: from 2.5.0 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-538",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eThe cooldown exists to keep a compromised release out of projects until it can be detected and retired. An attacker who controls a package owner account can defeat it by also retiring the currently locked release, so a malicious release reaches projects that rely on the local cooldown as soon as they run \u003ccode\u003emix deps.update\u003c/code\u003e, including automated dependency update jobs. The malicious release\u0027s code then runs when the dependency is compiled.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "The cooldown exists to keep a compromised release out of projects until it can be detected and retired. An attacker who controls a package owner account can defeat it by also retiring the currently locked release, so a malicious release reaches projects that rely on the local cooldown as soon as they run `mix deps.update`, including automated dependency update jobs. The malicious release\u0027s code then runs when the dependency is compiled."
                    }
                  ],
                  "value": "The cooldown exists to keep a compromised release out of projects until it can be detected and retired. An attacker who controls a package owner account can defeat it by also retiring the currently locked release, so a malicious release reaches projects that rely on the local cooldown as soon as they run mix deps.update, including automated dependency update jobs. The malicious release\u0027s code then runs when the dependency is compiled."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 7.1,
                "baseSeverity": "HIGH",
                "privilegesRequired": "HIGH",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:A/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-693",
                  "description": "CWE-693 Protection Mechanism Failure",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:31:58.926Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-pqhp-5x9x-69h7"
            },
            {
              "name": "EEF CNA record for CVE-2026-105668",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-105668.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-105668",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-105668"
            },
            {
              "name": "Introducing commit b4e665d in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/b4e665d46be8a5f81e8cbbe4c3a67058a19cf133"
            },
            {
              "name": "Fix commit eed2bdf in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/eed2bdf85320ae9e244629511c03f5f3f8c5d0b5"
            },
            {
              "name": "Fix commit 1b6fddf in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/1b6fddfeadd98ed26a143f60356efade0494e2ae"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. A retired locked release then no longer lifts the release-age cooldown for its package. A locked release with a security advisory still lifts it for its package and the direct dependencies of the locked release, only in the repository the package is locked from.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. A retired locked release then no longer lifts the release-age cooldown for its package. A locked release with a security advisory still lifts it for its package and the direct dependencies of the locked release, only in the repository the package is locked from."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. A retired locked release then no longer lifts the release-age cooldown for its package. A locked release with a security advisory still lifts it for its package and the direct dependencies of the locked release, only in the repository the package is locked from."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex release-age cooldown is lifted package-wide when the locked release is retired",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eEnforce the cooldown through an organization dependency policy instead of the local \u003ccode\u003ecooldown\u003c/code\u003e setting, or run \u003ccode\u003emix hex.audit\u003c/code\u003e before \u003ccode\u003emix deps.update\u003c/code\u003e and don\u0027t update a package whose locked release was retired until its replacement has been reviewed.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Enforce the cooldown through an organization dependency policy instead of the local `cooldown` setting, or run `mix hex.audit` before `mix deps.update` and don\u0027t update a package whose locked release was retired until its replacement has been reviewed."
                }
              ],
              "value": "Enforce the cooldown through an organization dependency policy instead of the local cooldown setting, or run mix hex.audit before mix deps.update and don\u0027t update a package whose locked release was retired until its replacement has been reviewed."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eLock \u003ccode\u003efoo 1.0.0\u003c/code\u003e in a project with \u003ccode\u003eHEX_COOLDOWN=7d\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003ePublish \u003ccode\u003efoo 1.0.1\u003c/code\u003e; \u003ccode\u003emix deps.update foo\u003c/code\u003e reports it as filtered by cooldown and keeps 1.0.0.\u003c/li\u003e\n\u003cli\u003eRetire \u003ccode\u003efoo 1.0.0\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eRun \u003ccode\u003emix deps.update foo\u003c/code\u003e again; it upgrades to the 1-hour-old 1.0.1.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Lock `foo 1.0.0` in a project with `HEX_COOLDOWN=7d`.\n2. Publish `foo 1.0.1`; `mix deps.update foo` reports it as filtered by cooldown and keeps 1.0.0.\n3. Retire `foo 1.0.0`.\n4. Run `mix deps.update foo` again; it upgrades to the 1-hour-old 1.0.1."
                }
              ],
              "value": "* Lock foo 1.0.0 in a project with HEX_COOLDOWN=7d.\n* Publish foo 1.0.1; mix deps.update foo reports it as filtered by cooldown and keeps 1.0.0.\n* Retire foo 1.0.0.\n* Run mix deps.update foo again; it upgrades to the 1-hour-old 1.0.1."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003eHex.RemoteConverger.build_cooldown_bypass/3\u003c/code\u003e adds \u003ccode\u003eunsafe_lock_bypass(old_lock)\u003c/code\u003e to the set of packages exempt from the cooldown.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eunsafe_lock_bypass/1\u003c/code\u003e adds a package\u0027s name, and the names of its locked children, whenever \u003ccode\u003eRegistry.retired/3\u003c/code\u003e or \u003ccode\u003eRegistry.advisories/3\u003c/code\u003e reports the locked version as unsafe.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eHex.Registry.Cooldown.versions/2\u003c/code\u003e returns every version unfiltered for any package name in that set, so freshly published versions become eligible as soon as the package is unlocked.\u003c/li\u003e\n\u003cli\u003ehex.pm lets the package owner retire any of their releases, so the owner controls the trigger. \u003ccode\u003eHex.Policy.Filter\u003c/code\u003e applies policy cooldowns without consulting the bypass set.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `Hex.RemoteConverger.build_cooldown_bypass/3` adds `unsafe_lock_bypass(old_lock)` to the set of packages exempt from the cooldown.\n2. `unsafe_lock_bypass/1` adds a package\u0027s name, and the names of its locked children, whenever `Registry.retired/3` or `Registry.advisories/3` reports the locked version as unsafe.\n3. `Hex.Registry.Cooldown.versions/2` returns every version unfiltered for any package name in that set, so freshly published versions become eligible as soon as the package is unlocked.\n4. hex.pm lets the package owner retire any of their releases, so the owner controls the trigger. `Hex.Policy.Filter` applies policy cooldowns without consulting the bypass set."
                }
              ],
              "value": "* Hex.RemoteConverger.build_cooldown_bypass/3 adds unsafe_lock_bypass(old_lock) to the set of packages exempt from the cooldown.\n* unsafe_lock_bypass/1 adds a package\u0027s name, and the names of its locked children, whenever Registry.retired/3 or Registry.advisories/3 reports the locked version as unsafe.\n* Hex.Registry.Cooldown.versions/2 returns every version unfiltered for any package name in that set, so freshly published versions become eligible as soon as the package is unlocked.\n* hex.pm lets the package owner retire any of their releases, so the owner controls the trigger. Hex.Policy.Filter applies policy cooldowns without consulting the bypass set."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-105668",
        "datePublished": "2026-10-12T15:31:58.926Z",
        "dateReserved": "2026-10-07T22:15:01.885Z",
        "dateUpdated": "2026-10-12T15:31:58.926Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-105280 (GCVE-0-2026-105280)

    Vulnerability from cvelistv5 – Published: 2026-10-12 15:30 – Updated: 2026-10-12 15:30
    VLAI
    Title
    Hex writes unverified package tarballs to standard output in mix hex.package fetch
    Summary
    Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that mix hex.package fetch PACKAGE VERSION --output - writes to standard output. Hex compares a fetched tarball's inner and outer checksums with the repository's signed registry before writing it to a file or unpacking it. The standard output branch of mix hex.package fetch writes the bytes returned by Hex.SCM.fetch/3 without that comparison, and Hex.SCM.fetch/3 doesn't verify freshly downloaded tarballs itself. When a mirror configured with HEX_MIRROR_URL or mirror_url serves altered bytes, the command prints them and exits successfully, while the same fetch with --output FILE fails with a checksum mismatch. Hex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the x-hex-message header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror's files. This happens even when the checksum check then fails, because the archive is already on standard output. This issue affects hex: from 0.20.2 before 2.5.2.
    CWE
    • CWE-354 - Improper Validation of Integrity Check Value
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.20.2 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: d1f5a085d9d4748e1f7d195e4bc39ebd77c28d9c , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Package\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.package.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Package\u0027:run/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.20.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Mix.Tasks.Hex.Package\u0027",
                "\u0027Elixir.Hex.SCM\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/mix/tasks/hex.package.ex",
                "lib/hex/scm.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Package\u0027:run/1"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "8a14632ca6ba8a8afd2a3f2098bc267c13e13d93",
                      "status": "unaffected"
                    },
                    {
                      "at": "69489f8b74213f03db10169e6e5407e6d5fee512",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "d1f5a085d9d4748e1f7d195e4bc39ebd77c28d9c",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects \u003ccode\u003emix hex.package fetch\u003c/code\u003e with \u003ccode\u003e--output -\u003c/code\u003e when packages are downloaded through a mirror set with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e. Downloads directly from the repository over HTTPS aren\u0027t affected unless TLS verification is broken.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects `mix hex.package fetch` with `--output -` when packages are downloaded through a mirror set with `HEX_MIRROR_URL` or `mirror_url`. Downloads directly from the repository over HTTPS aren\u0027t affected unless TLS verification is broken."
                }
              ],
              "value": "Affects mix hex.package fetch with --output - when packages are downloaded through a mirror set with HEX_MIRROR_URL or mirror_url. Downloads directly from the repository over HTTPS aren\u0027t affected unless TLS verification is broken."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.20.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:01:30.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that \u003ccode\u003emix hex.package fetch PACKAGE VERSION --output -\u003c/code\u003e writes to standard output.\u003c/p\u003e\n\u003cp\u003eHex compares a fetched tarball\u0027s inner and outer checksums with the repository\u0027s signed registry before writing it to a file or unpacking it. The standard output branch of \u003ccode\u003emix hex.package fetch\u003c/code\u003e writes the bytes returned by \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e without that comparison, and \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e doesn\u0027t verify freshly downloaded tarballs itself. When a mirror configured with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e serves altered bytes, the command prints them and exits successfully, while the same fetch with \u003ccode\u003e--output FILE\u003c/code\u003e fails with a checksum mismatch.\u003c/p\u003e\n\u003cp\u003eHex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the \u003ccode\u003ex-hex-message\u003c/code\u003e header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror\u0027s files. This happens even when the checksum check then fails, because the archive is already on standard output.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.20.2 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that `mix hex.package fetch PACKAGE VERSION --output -` writes to standard output.\n\nHex compares a fetched tarball\u0027s inner and outer checksums with the repository\u0027s signed registry before writing it to a file or unpacking it. The standard output branch of `mix hex.package fetch` writes the bytes returned by `Hex.SCM.fetch/3` without that comparison, and `Hex.SCM.fetch/3` doesn\u0027t verify freshly downloaded tarballs itself. When a mirror configured with `HEX_MIRROR_URL` or `mirror_url` serves altered bytes, the command prints them and exits successfully, while the same fetch with `--output FILE` fails with a checksum mismatch.\n\nHex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the `x-hex-message` header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror\u0027s files. This happens even when the checksum check then fails, because the archive is already on standard output.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
                }
              ],
              "value": "Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that mix hex.package fetch PACKAGE VERSION --output - writes to standard output.\n\nHex compares a fetched tarball\u0027s inner and outer checksums with the repository\u0027s signed registry before writing it to a file or unpacking it. The standard output branch of mix hex.package fetch writes the bytes returned by Hex.SCM.fetch/3 without that comparison, and Hex.SCM.fetch/3 doesn\u0027t verify freshly downloaded tarballs itself. When a mirror configured with HEX_MIRROR_URL or mirror_url serves altered bytes, the command prints them and exits successfully, while the same fetch with --output FILE fails with a checksum mismatch.\n\nHex also prints diagnostics to standard output while the command runs: the body of a failed HTTP response from the update check or a registry fetch, and API warnings from the x-hex-message header. A mirror that answers one of those requests with an error whose body is a tar archive gets that archive written to standard output ahead of the verified tarball, so a pipeline that unpacks standard output extracts the mirror\u0027s files. This happens even when the checksum check then fails, because the archive is already on standard output.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-186",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eHex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe \u003ccode\u003emix hex.package fetch --output -\u003c/code\u003e into another tool, such as an unpacker, a vendoring step or an installer, receive whatever the mirror served, so the mirror operator can deliver modified package contents that downstream steps treat as the published release.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "Hex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe `mix hex.package fetch --output -` into another tool, such as an unpacker, a vendoring step or an installer, receive whatever the mirror served, so the mirror operator can deliver modified package contents that downstream steps treat as the published release."
                    }
                  ],
                  "value": "Hex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe mix hex.package fetch --output - into another tool, such as an unpacker, a vendoring step or an installer, receive whatever the mirror served, so the mirror operator can deliver modified package contents that downstream steps treat as the published release."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 6.9,
                "baseSeverity": "MEDIUM",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "HIGH",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-354",
                  "description": "CWE-354 Improper Validation of Integrity Check Value",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:30:14.126Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-98jr-23pm-vj7c"
            },
            {
              "name": "EEF CNA record for CVE-2026-105280",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-105280.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-105280",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-105280"
            },
            {
              "name": "Introducing commit d1f5a08 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/d1f5a085d9d4748e1f7d195e4bc39ebd77c28d9c"
            },
            {
              "name": "Fix commit 8a14632 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/8a14632ca6ba8a8afd2a3f2098bc267c13e13d93"
            },
            {
              "name": "Fix commit 69489f8 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/69489f8b74213f03db10169e6e5407e6d5fee512"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. \u003ccode\u003emix hex.package fetch PACKAGE VERSION --output -\u003c/code\u003e then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. `mix hex.package fetch PACKAGE VERSION --output -` then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. mix hex.package fetch PACKAGE VERSION --output - then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex writes unverified package tarballs to standard output in mix hex.package fetch",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eWrite the tarball to a file with \u003ccode\u003e--output FILE\u003c/code\u003e, which verifies the checksums, and read that file instead of standard output.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Write the tarball to a file with `--output FILE`, which verifies the checksums, and read that file instead of standard output."
                }
              ],
              "value": "Write the tarball to a file with --output FILE, which verifies the checksums, and read that file instead of standard output."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eSet \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e to a server that returns modified bytes for \u003ccode\u003etarballs/decimal-2.4.1.tar\u003c/code\u003e and proxies everything else to repo.hex.pm.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emix hex.package fetch decimal 2.4.1 --output -\u003c/code\u003e prints the modified bytes and exits 0.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003emix hex.package fetch decimal 2.4.1 --output decimal.tar\u003c/code\u003e fails with \u003ccode\u003eChecksum mismatch against registry (outer)\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Set `HEX_MIRROR_URL` to a server that returns modified bytes for `tarballs/decimal-2.4.1.tar` and proxies everything else to repo.hex.pm.\n2. `mix hex.package fetch decimal 2.4.1 --output -` prints the modified bytes and exits 0.\n3. `mix hex.package fetch decimal 2.4.1 --output decimal.tar` fails with `Checksum mismatch against registry (outer)`."
                }
              ],
              "value": "* Set HEX_MIRROR_URL to a server that returns modified bytes for tarballs/decimal-2.4.1.tar and proxies everything else to repo.hex.pm.\n* mix hex.package fetch decimal 2.4.1 --output - prints the modified bytes and exits 0.\n* mix hex.package fetch decimal 2.4.1 --output decimal.tar fails with Checksum mismatch against registry (outer)."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003emix hex.package fetch PACKAGE VERSION --output -\u003c/code\u003e calls \u003ccode\u003efetch_tarball!/3\u003c/code\u003e, which calls \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eFor a fresh download, \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e writes the response body to the cache and returns it without comparing it to the registry checksum.\u003c/li\u003e\n\u003cli\u003eThe standard output branch passes those bytes to \u003ccode\u003eIO.binwrite/1\u003c/code\u003e. The file and \u003ccode\u003e--unpack\u003c/code\u003e branches call \u003ccode\u003everify_inner_checksum!/4\u003c/code\u003e and \u003ccode\u003everify_outer_checksum!/4\u003c/code\u003e first.\u003c/li\u003e\n\u003cli\u003eWhile the task runs, Hex prints messages with \u003ccode\u003eHex.Shell.info/1\u003c/code\u003e, which writes to standard output. \u003ccode\u003eHex.Utils.print_error_result/1\u003c/code\u003e prints the body of an error response that way; the update checker calls it when its request for \u003ccode\u003einstalls/hex-1.x.csv\u003c/code\u003e fails, and \u003ccode\u003eHex.Registry.Server\u003c/code\u003e calls it when a registry fetch fails and the cached registry is used. \u003ccode\u003eHex.HTTP\u003c/code\u003e prints the \u003ccode\u003ex-hex-message\u003c/code\u003e warning of each response the same way. These are printed before the tarball is written, so the mirror chooses bytes that come before the tarball on standard output.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `mix hex.package fetch PACKAGE VERSION --output -` calls `fetch_tarball!/3`, which calls `Hex.SCM.fetch/3`.\n2. For a fresh download, `Hex.SCM.fetch/3` writes the response body to the cache and returns it without comparing it to the registry checksum.\n3. The standard output branch passes those bytes to `IO.binwrite/1`. The file and `--unpack` branches call `verify_inner_checksum!/4` and `verify_outer_checksum!/4` first.\n4. While the task runs, Hex prints messages with `Hex.Shell.info/1`, which writes to standard output. `Hex.Utils.print_error_result/1` prints the body of an error response that way; the update checker calls it when its request for `installs/hex-1.x.csv` fails, and `Hex.Registry.Server` calls it when a registry fetch fails and the cached registry is used. `Hex.HTTP` prints the `x-hex-message` warning of each response the same way. These are printed before the tarball is written, so the mirror chooses bytes that come before the tarball on standard output."
                }
              ],
              "value": "* mix hex.package fetch PACKAGE VERSION --output - calls fetch_tarball!/3, which calls Hex.SCM.fetch/3.\n* For a fresh download, Hex.SCM.fetch/3 writes the response body to the cache and returns it without comparing it to the registry checksum.\n* The standard output branch passes those bytes to IO.binwrite/1. The file and --unpack branches call verify_inner_checksum!/4 and verify_outer_checksum!/4 first.\n* While the task runs, Hex prints messages with Hex.Shell.info/1, which writes to standard output. Hex.Utils.print_error_result/1 prints the body of an error response that way; the update checker calls it when its request for installs/hex-1.x.csv fails, and Hex.Registry.Server calls it when a registry fetch fails and the cached registry is used. Hex.HTTP prints the x-hex-message warning of each response the same way. These are printed before the tarball is written, so the mirror chooses bytes that come before the tarball on standard output."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-105280",
        "datePublished": "2026-10-12T15:30:14.126Z",
        "dateReserved": "2026-10-08T13:45:02.134Z",
        "dateUpdated": "2026-10-12T15:30:14.126Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-96618 (GCVE-0-2026-96618)

    Vulnerability from cvelistv5 – Published: 2026-10-12 15:29 – Updated: 2026-10-12 15:29
    VLAI
    Title
    Hex exhausts memory and disk on oversized or compressed responses from an untrusted mirror
    Summary
    Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running mix deps.get, mix deps.update, mix hex.package fetch or mix hex.docs fetch. Hex treats a mirror configured with HEX_MIRROR_URL, HEX_MIRROR or mirror_url as untrusted: it doesn't send credentials to it, and it checks registry signatures and package checksums that the mirror can't forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run. Hex.HTTP.request/5 reads the whole response body into memory and decompresses it with :zlib.gunzip/1 whenever the response's Content-Encoding contains gzip, with no limit on the compressed or decompressed size. Hex doesn't ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses. Package tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into deps/<app> in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry. mix hex.docs fetch, and mix hex.docs offline when docs are missing, write the docs tarball to disk and extract it with :mix_hex_erl_tar.extract/2 without the 16 MiB compressed and 128 MiB decompressed limits that mix_hex_tarball:unpack_docs/3 applies. The signed registry doesn't cover docs tarballs, so nothing checks them. Registry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq. This issue affects hex: from 0.11.2 before 2.5.2.
    CWE
    • CWE-409 - Improper Handling of Highly Compressed Data (Data Amplification)
    • CWE-770 - Allocation of Resources Without Limits or Throttling
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.11.2 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 51ea632424fb6ea8765148f96dc25dfeb526b1f8 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP\u0027",
                "\u0027Elixir.Hex.SCM\u0027",
                "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/http.ex",
                "lib/hex/scm.ex",
                "lib/mix/tasks/hex.docs.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP\u0027:request/5"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.11.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP\u0027",
                "\u0027Elixir.Hex.SCM\u0027",
                "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/http.ex",
                "lib/hex/scm.ex",
                "lib/mix/tasks/hex.docs.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP\u0027:request/5"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:fetch/3"
                },
                {
                  "name": "\u0027Elixir.Hex.SCM\u0027:update/1"
                },
                {
                  "name": "\u0027Elixir.Mix.Tasks.Hex.Docs\u0027:run/1"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "bb5189eade682c5fc3f98d9725973a7beb4e1deb",
                      "status": "unaffected"
                    },
                    {
                      "at": "08956100a8283ba500a123e5539ac64d5d7e91d8",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "51ea632424fb6ea8765148f96dc25dfeb526b1f8",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects users who fetch packages or docs through a mirror set with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e, \u003ccode\u003eHEX_MIRROR\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e. Fetches from repo.hex.pm over HTTPS aren\u0027t affected unless TLS verification is broken. A trusted mirror (\u003ccode\u003eHEX_TRUSTED_MIRROR_URL\u003c/code\u003e) or a self-hosted repository can do the same, but Hex already trusts those with credentials.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects users who fetch packages or docs through a mirror set with `HEX_MIRROR_URL`, `HEX_MIRROR` or `mirror_url`. Fetches from repo.hex.pm over HTTPS aren\u0027t affected unless TLS verification is broken. A trusted mirror (`HEX_TRUSTED_MIRROR_URL`) or a self-hosted repository can do the same, but Hex already trusts those with credentials."
                }
              ],
              "value": "Affects users who fetch packages or docs through a mirror set with HEX_MIRROR_URL, HEX_MIRROR or mirror_url. Fetches from repo.hex.pm over HTTPS aren\u0027t affected unless TLS verification is broken. A trusted mirror (HEX_TRUSTED_MIRROR_URL) or a self-hosted repository can do the same, but Hex already trusts those with credentials."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.11.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T13:00:30.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running \u003ccode\u003emix deps.get\u003c/code\u003e, \u003ccode\u003emix deps.update\u003c/code\u003e, \u003ccode\u003emix hex.package fetch\u003c/code\u003e or \u003ccode\u003emix hex.docs fetch\u003c/code\u003e.\u003c/p\u003e\n\u003cp\u003eHex treats a mirror configured with \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e, \u003ccode\u003eHEX_MIRROR\u003c/code\u003e or \u003ccode\u003emirror_url\u003c/code\u003e as untrusted: it doesn\u0027t send credentials to it, and it checks registry signatures and package checksums that the mirror can\u0027t forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003eHex.HTTP.request/5\u003c/code\u003e reads the whole response body into memory and decompresses it with \u003ccode\u003e:zlib.gunzip/1\u003c/code\u003e whenever the response\u0027s \u003ccode\u003eContent-Encoding\u003c/code\u003e contains \u003ccode\u003egzip\u003c/code\u003e, with no limit on the compressed or decompressed size. Hex doesn\u0027t ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses.\u003c/p\u003e\n\u003cp\u003ePackage tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into \u003ccode\u003edeps/\u0026lt;app\u0026gt;\u003c/code\u003e in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003emix hex.docs fetch\u003c/code\u003e, and \u003ccode\u003emix hex.docs offline\u003c/code\u003e when docs are missing, write the docs tarball to disk and extract it with \u003ccode\u003e:mix_hex_erl_tar.extract/2\u003c/code\u003e without the 16 MiB compressed and 128 MiB decompressed limits that \u003ccode\u003emix_hex_tarball:unpack_docs/3\u003c/code\u003e applies. The signed registry doesn\u0027t cover docs tarballs, so nothing checks them.\u003c/p\u003e\n\u003cp\u003eRegistry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in \u003ca href=\"https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq\" rel=\"noopener noreferrer\"\u003ehttps://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.11.2 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running `mix deps.get`, `mix deps.update`, `mix hex.package fetch` or `mix hex.docs fetch`.\n\nHex treats a mirror configured with `HEX_MIRROR_URL`, `HEX_MIRROR` or `mirror_url` as untrusted: it doesn\u0027t send credentials to it, and it checks registry signatures and package checksums that the mirror can\u0027t forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run.\n\n`Hex.HTTP.request/5` reads the whole response body into memory and decompresses it with `:zlib.gunzip/1` whenever the response\u0027s `Content-Encoding` contains `gzip`, with no limit on the compressed or decompressed size. Hex doesn\u0027t ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses.\n\nPackage tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into `deps/\u003capp\u003e` in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry.\n\n`mix hex.docs fetch`, and `mix hex.docs offline` when docs are missing, write the docs tarball to disk and extract it with `:mix_hex_erl_tar.extract/2` without the 16 MiB compressed and 128 MiB decompressed limits that `mix_hex_tarball:unpack_docs/3` applies. The signed registry doesn\u0027t cover docs tarballs, so nothing checks them.\n\nRegistry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq.\n\nThis issue affects hex: from 0.11.2 before 2.5.2."
                }
              ],
              "value": "Improper Handling of Highly Compressed Data (Data Amplification) vulnerability in hexpm hex allows an untrusted package mirror to exhaust the memory or disk space of the machine running mix deps.get, mix deps.update, mix hex.package fetch or mix hex.docs fetch.\n\nHex treats a mirror configured with HEX_MIRROR_URL, HEX_MIRROR or mirror_url as untrusted: it doesn\u0027t send credentials to it, and it checks registry signatures and package checksums that the mirror can\u0027t forge. Several response paths consume memory or disk in proportion to what the mirror sends before any of those checks run.\n\nHex.HTTP.request/5 reads the whole response body into memory and decompresses it with :zlib.gunzip/1 whenever the response\u0027s Content-Encoding contains gzip, with no limit on the compressed or decompressed size. Hex doesn\u0027t ask for compressed responses, so the server decides whether this step runs. It applies to registry, package, docs and API responses.\n\nPackage tarballs have no download size limit. Hex 2.5.1 holds the whole tarball in memory and writes it to the cache, and the development branch streams it to a temporary file; the 16 MiB tarball limit is checked only when the file is unpacked. The tarball is then unpacked, into deps/\u003capp\u003e in 2.5.1 and into a staging directory on the development branch, before its checksums are compared with the registry.\n\nmix hex.docs fetch, and mix hex.docs offline when docs are missing, write the docs tarball to disk and extract it with :mix_hex_erl_tar.extract/2 without the 16 MiB compressed and 128 MiB decompressed limits that mix_hex_tarball:unpack_docs/3 applies. The signed registry doesn\u0027t cover docs tarballs, so nothing checks them.\n\nRegistry responses are also decompressed before their signature is checked, in hex_core code that Hex vendors; that part is tracked in https://github.com/hexpm/hex_core/security/advisories/GHSA-7c4r-cgf9-9jmq.\n\nThis issue affects hex: from 0.11.2 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eA mirror operator, or an attacker who controls the mirror\u0027s responses, can make Hex allocate memory or write data far larger than what it sent: in tests against Hex main 851b938, a 65 KB gzip-encoded response decompressed to 64 MiB in memory, a 17 MiB tarball was downloaded in full despite the 16 MiB limit, and a 131 KB docs tarball wrote 129 MiB to disk. Larger responses stop the Erlang VM running Mix or fill the disk, failing builds and CI jobs, and a full disk affects other processes on the machine. No package code has to run, and the mirror doesn\u0027t need the repository\u0027s signing key.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "A mirror operator, or an attacker who controls the mirror\u0027s responses, can make Hex allocate memory or write data far larger than what it sent: in tests against Hex main 851b938, a 65 KB gzip-encoded response decompressed to 64 MiB in memory, a 17 MiB tarball was downloaded in full despite the 16 MiB limit, and a 131 KB docs tarball wrote 129 MiB to disk. Larger responses stop the Erlang VM running Mix or fill the disk, failing builds and CI jobs, and a full disk affects other processes on the machine. No package code has to run, and the mirror doesn\u0027t need the repository\u0027s signing key."
                    }
                  ],
                  "value": "A mirror operator, or an attacker who controls the mirror\u0027s responses, can make Hex allocate memory or write data far larger than what it sent: in tests against Hex main 851b938, a 65 KB gzip-encoded response decompressed to 64 MiB in memory, a 17 MiB tarball was downloaded in full despite the 16 MiB limit, and a 131 KB docs tarball wrote 129 MiB to disk. Larger responses stop the Erlang VM running Mix or fill the disk, failing builds and CI jobs, and a full disk affects other processes on the machine. No package code has to run, and the mirror doesn\u0027t need the repository\u0027s signing key."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2.1,
                "baseSeverity": "LOW",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "LOW",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-409",
                  "description": "CWE-409 Improper Handling of Highly Compressed Data (Data Amplification)",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            },
            {
              "descriptions": [
                {
                  "cweId": "CWE-770",
                  "description": "CWE-770 Allocation of Resources Without Limits or Throttling",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:29:19.117Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-gf42-pg2f-63jp"
            },
            {
              "name": "EEF CNA record for CVE-2026-96618",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-96618.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-96618",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-96618"
            },
            {
              "name": "Introducing commit 51ea632 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/51ea632424fb6ea8765148f96dc25dfeb526b1f8"
            },
            {
              "name": "Fix commit bb5189e in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/bb5189eade682c5fc3f98d9725973a7beb4e1deb"
            },
            {
              "name": "Fix commit 0895610 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/08956100a8283ba500a123e5539ac64d5d7e91d8"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. Hex then stops downloading a registry file, package, docs tarball or other file from a repository or mirror once it\u0027s larger than 16 MiB, including after decompressing a gzip-encoded response, and checks packages against the registry checksum before writing them to the package cache or unpacking a cached copy.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. Hex then stops downloading a registry file, package, docs tarball or other file from a repository or mirror once it\u0027s larger than 16 MiB, including after decompressing a gzip-encoded response, and checks packages against the registry checksum before writing them to the package cache or unpacking a cached copy."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. Hex then stops downloading a registry file, package, docs tarball or other file from a repository or mirror once it\u0027s larger than 16 MiB, including after decompressing a gzip-encoded response, and checks packages against the registry checksum before writing them to the package cache or unpacking a cached copy."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex exhausts memory and disk on oversized or compressed responses from an untrusted mirror",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eFetch from repo.hex.pm or a mirror you operate. Running Mix under operating system memory and disk limits, such as container limits, confines the effect to that container.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Fetch from repo.hex.pm or a mirror you operate. Running Mix under operating system memory and disk limits, such as container limits, confines the effect to that container."
                }
              ],
              "value": "Fetch from repo.hex.pm or a mirror you operate. Running Mix under operating system memory and disk limits, such as container limits, confines the effect to that container."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eRun a loopback HTTP server that answers with a 65,255-byte gzip stream decompressing to 64 MiB and \u003ccode\u003eContent-Encoding: gzip\u003c/code\u003e. \u003ccode\u003eHex.HTTP.request(:get, url, %{}, nil)\u003c/code\u003e returns a 67,108,864-byte body; peak RSS was 220 MiB, against 91 MiB for an uncompressed control.\u003c/li\u003e\n\u003cli\u003eServe a 17 MiB file as a package tarball. \u003ccode\u003eHex.Repo.get_tarball/3\u003c/code\u003e returns all of it, and only the following unpack fails with \u003ccode\u003e{:tarball, :too_big}\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eServe a 131,574-byte docs tarball containing a 129 MiB file and set \u003ccode\u003eHEX_MIRROR_URL\u003c/code\u003e to the server. \u003ccode\u003emix hex.docs fetch probe 1.0.0\u003c/code\u003e writes the 129 MiB file and reports success.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Run a loopback HTTP server that answers with a 65,255-byte gzip stream decompressing to 64 MiB and `Content-Encoding: gzip`. `Hex.HTTP.request(:get, url, %{}, nil)` returns a 67,108,864-byte body; peak RSS was 220 MiB, against 91 MiB for an uncompressed control.\n2. Serve a 17 MiB file as a package tarball. `Hex.Repo.get_tarball/3` returns all of it, and only the following unpack fails with `{:tarball, :too_big}`.\n3. Serve a 131,574-byte docs tarball containing a 129 MiB file and set `HEX_MIRROR_URL` to the server. `mix hex.docs fetch probe 1.0.0` writes the 129 MiB file and reports success."
                }
              ],
              "value": "* Run a loopback HTTP server that answers with a 65,255-byte gzip stream decompressing to 64 MiB and Content-Encoding: gzip. Hex.HTTP.request(:get, url, %{}, nil) returns a 67,108,864-byte body; peak RSS was 220 MiB, against 91 MiB for an uncompressed control.\n* Serve a 17 MiB file as a package tarball. Hex.Repo.get_tarball/3 returns all of it, and only the following unpack fails with {:tarball, :too_big}.\n* Serve a 131,574-byte docs tarball containing a 129 MiB file and set HEX_MIRROR_URL to the server. mix hex.docs fetch probe 1.0.0 writes the 129 MiB file and reports success."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003eHex.HTTP.request/5\u003c/code\u003e calls \u003ccode\u003e:httpc.request/5\u003c/code\u003e with \u003ccode\u003ebody_format: :binary\u003c/code\u003e, so the whole body is held in memory, and then calls \u003ccode\u003e:zlib.gunzip/1\u003c/code\u003e when the \u003ccode\u003econtent-encoding\u003c/code\u003e header contains \u003ccode\u003egzip\u003c/code\u003e. Hex doesn\u0027t send \u003ccode\u003eAccept-Encoding\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003eWhen \u003ccode\u003emirror_url\u003c/code\u003e is set, \u003ccode\u003eHex.Repo\u003c/code\u003e sends registry, tarball and docs requests to the mirror and marks it untrusted, so no credentials are sent to it.\u003c/li\u003e\n\u003cli\u003eHex 2.5.1: \u003ccode\u003eHex.SCM.fetch/3\u003c/code\u003e writes the body returned by \u003ccode\u003eHex.Repo.get_tarball/3\u003c/code\u003e to the cache. \u003ccode\u003eHex.SCM.update/1\u003c/code\u003e deletes \u003ccode\u003edeps/\u0026lt;app\u0026gt;\u003c/code\u003e, unpacks the tarball into it with \u003ccode\u003eHex.Tar.unpack!/2\u003c/code\u003e and compares the inner and outer checksums afterwards. Development branch: \u003ccode\u003eHex.Repo.get_tarball_to_file/4\u003c/code\u003e streams the tarball to a temporary file without counting bytes; the file is renamed into the cache and unpacked into a staging directory before the checksums are compared.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003eMix.Tasks.Hex.Docs\u003c/code\u003e writes the body returned by \u003ccode\u003eHex.Repo.get_docs/3\u003c/code\u003e to disk and calls \u003ccode\u003e:mix_hex_erl_tar.extract/2\u003c/code\u003e with \u003ccode\u003e[:compressed, cwd: ...]\u003c/code\u003e and no \u003ccode\u003emax_size\u003c/code\u003e, while \u003ccode\u003emix_hex_tarball:unpack_docs/3\u003c/code\u003e enforces a 16 MiB compressed and 128 MiB decompressed limit.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `Hex.HTTP.request/5` calls `:httpc.request/5` with `body_format: :binary`, so the whole body is held in memory, and then calls `:zlib.gunzip/1` when the `content-encoding` header contains `gzip`. Hex doesn\u0027t send `Accept-Encoding`.\n2. When `mirror_url` is set, `Hex.Repo` sends registry, tarball and docs requests to the mirror and marks it untrusted, so no credentials are sent to it.\n3. Hex 2.5.1: `Hex.SCM.fetch/3` writes the body returned by `Hex.Repo.get_tarball/3` to the cache. `Hex.SCM.update/1` deletes `deps/\u003capp\u003e`, unpacks the tarball into it with `Hex.Tar.unpack!/2` and compares the inner and outer checksums afterwards. Development branch: `Hex.Repo.get_tarball_to_file/4` streams the tarball to a temporary file without counting bytes; the file is renamed into the cache and unpacked into a staging directory before the checksums are compared.\n4. `Mix.Tasks.Hex.Docs` writes the body returned by `Hex.Repo.get_docs/3` to disk and calls `:mix_hex_erl_tar.extract/2` with `[:compressed, cwd: ...]` and no `max_size`, while `mix_hex_tarball:unpack_docs/3` enforces a 16 MiB compressed and 128 MiB decompressed limit."
                }
              ],
              "value": "* Hex.HTTP.request/5 calls :httpc.request/5 with body_format: :binary, so the whole body is held in memory, and then calls :zlib.gunzip/1 when the content-encoding header contains gzip. Hex doesn\u0027t send Accept-Encoding.\n* When mirror_url is set, Hex.Repo sends registry, tarball and docs requests to the mirror and marks it untrusted, so no credentials are sent to it.\n* Hex 2.5.1: Hex.SCM.fetch/3 writes the body returned by Hex.Repo.get_tarball/3 to the cache. Hex.SCM.update/1 deletes deps/\u003capp\u003e, unpacks the tarball into it with Hex.Tar.unpack!/2 and compares the inner and outer checksums afterwards. Development branch: Hex.Repo.get_tarball_to_file/4 streams the tarball to a temporary file without counting bytes; the file is renamed into the cache and unpacked into a staging directory before the checksums are compared.\n* Mix.Tasks.Hex.Docs writes the body returned by Hex.Repo.get_docs/3 to disk and calls :mix_hex_erl_tar.extract/2 with [:compressed, cwd: ...] and no max_size, while mix_hex_tarball:unpack_docs/3 enforces a 16 MiB compressed and 128 MiB decompressed limit."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-96618",
        "datePublished": "2026-10-12T15:29:19.117Z",
        "dateReserved": "2026-10-10T13:00:02.352Z",
        "dateUpdated": "2026-10-12T15:29:19.117Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-103503 (GCVE-0-2026-103503)

    Vulnerability from cvelistv5 – Published: 2026-10-12 15:17 – Updated: 2026-10-12 15:17
    VLAI
    Title
    Hex trusts its bundled CA certificates when cacerts_path is set
    Summary
    Improper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex's bundled CA store, to impersonate that host to users who set cacerts_path to a CA store that leaves that CA out. cacerts_path (HEX_CACERTS_PATH) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. Hex.HTTP.SSL.ssl_opts/1 passes the configured store as the cacerts option, but builds the partial_chain callback from the bundled store whether cacerts_path is set or not. Hex.HTTP.SSL.partial_chain/2 accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn't contain that CA. Hostname verification still applies. This issue affects hex: from 0.20.2 before 2.5.2.
    CWE
    • CWE-295 - Improper Certificate Validation
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.20.2 , < 2.5.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: c9b26a46928bfcd546773571e09c1d05f4cd9fb7 , < * (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP.SSL\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=repository_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/http/ssl.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:ssl_opts/1"
                },
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:partial_chain/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.5.2",
                  "status": "affected",
                  "version": "0.20.2",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.HTTP.SSL\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/http/ssl.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:ssl_opts/1"
                },
                {
                  "name": "\u0027Elixir.Hex.HTTP.SSL\u0027:partial_chain/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "changes": [
                    {
                      "at": "5f5a2136c7cf5991b6e8a30d645ca9f8e74b0785",
                      "status": "unaffected"
                    },
                    {
                      "at": "6232a6498015e559743bec4f4fbec9138837cec8",
                      "status": "unaffected"
                    }
                  ],
                  "lessThan": "*",
                  "status": "affected",
                  "version": "c9b26a46928bfcd546773571e09c1d05f4cd9fb7",
                  "versionType": "git"
                }
              ]
            }
          ],
          "configurations": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eAffects users who set \u003ccode\u003ecacerts_path\u003c/code\u003e or \u003ccode\u003eHEX_CACERTS_PATH\u003c/code\u003e to a CA store that leaves out some of the CAs bundled with Hex. Users who don\u0027t set it trust the bundled store already and aren\u0027t affected.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Affects users who set `cacerts_path` or `HEX_CACERTS_PATH` to a CA store that leaves out some of the CAs bundled with Hex. Users who don\u0027t set it trust the bundled store already and aren\u0027t affected."
                }
              ],
              "value": "Affects users who set cacerts_path or HEX_CACERTS_PATH to a CA store that leaves out some of the CAs bundled with Hex. Users who don\u0027t set it trust the bundled store already and aren\u0027t affected."
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.5.2",
                      "versionStartIncluding": "0.20.2",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Peter Ullrich"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Eric Meadows-J\u00f6nsson"
            },
            {
              "lang": "en",
              "type": "analyst",
              "value": "Jonatan M\u00e4nnchen / EEF"
            }
          ],
          "dateAssigned": "2026-10-10T12:59:48.000Z",
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eImproper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex\u0027s bundled CA store, to impersonate that host to users who set \u003ccode\u003ecacerts_path\u003c/code\u003e to a CA store that leaves that CA out.\u003c/p\u003e\n\u003cp\u003e\u003ccode\u003ecacerts_path\u003c/code\u003e (\u003ccode\u003eHEX_CACERTS_PATH\u003c/code\u003e) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. \u003ccode\u003eHex.HTTP.SSL.ssl_opts/1\u003c/code\u003e passes the configured store as the \u003ccode\u003ecacerts\u003c/code\u003e option, but builds the \u003ccode\u003epartial_chain\u003c/code\u003e callback from the bundled store whether \u003ccode\u003ecacerts_path\u003c/code\u003e is set or not. \u003ccode\u003eHex.HTTP.SSL.partial_chain/2\u003c/code\u003e accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn\u0027t contain that CA. Hostname verification still applies.\u003c/p\u003e\n\u003cp\u003eThis issue affects hex: from 0.20.2 before 2.5.2.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Improper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex\u0027s bundled CA store, to impersonate that host to users who set `cacerts_path` to a CA store that leaves that CA out.\n\n`cacerts_path` (`HEX_CACERTS_PATH`) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. `Hex.HTTP.SSL.ssl_opts/1` passes the configured store as the `cacerts` option, but builds the `partial_chain` callback from the bundled store whether `cacerts_path` is set or not. `Hex.HTTP.SSL.partial_chain/2` accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn\u0027t contain that CA. Hostname verification still applies.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
                }
              ],
              "value": "Improper Certificate Validation vulnerability in hexpm hex allows an attacker who can intercept HTTPS connections, and holds a certificate for a Hex host issued by a CA in Hex\u0027s bundled CA store, to impersonate that host to users who set cacerts_path to a CA store that leaves that CA out.\n\ncacerts_path (HEX_CACERTS_PATH) is documented as the path to the CA certificate store, used instead of the CA bundle that ships with Hex. Hex.HTTP.SSL.ssl_opts/1 passes the configured store as the cacerts option, but builds the partial_chain callback from the bundled store whether cacerts_path is set or not. Hex.HTTP.SSL.partial_chain/2 accepts a server chain when any certificate in it has the same public key as a bundled CA certificate, so a chain that leads to a bundled CA passes verification although the configured store doesn\u0027t contain that CA. Hostname verification still applies.\n\nThis issue affects hex: from 0.20.2 before 2.5.2."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-94",
              "descriptions": [
                {
                  "lang": "en",
                  "supportingMedia": [
                    {
                      "base64": false,
                      "type": "text/html",
                      "value": "\u003cp\u003eUsers set \u003ccode\u003ecacerts_path\u003c/code\u003e to limit which CAs can authenticate Hex\u0027s servers, for example to their organization\u0027s internal CA. Every CA in Hex\u0027s bundled store can still authenticate those servers, so a certificate mis-issued by one of those CAs, or obtained through compromised domain validation, lets an attacker on the network path impersonate hex.pm, repo.hex.pm, a self-hosted repository or a mirror. The attacker receives the API keys, OAuth tokens and repository keys Hex sends, and can alter API responses. Registry signatures and package checksums still prevent changes to registry contents and packages.\u003c/p\u003e"
                    },
                    {
                      "base64": false,
                      "type": "text/markdown",
                      "value": "Users set `cacerts_path` to limit which CAs can authenticate Hex\u0027s servers, for example to their organization\u0027s internal CA. Every CA in Hex\u0027s bundled store can still authenticate those servers, so a certificate mis-issued by one of those CAs, or obtained through compromised domain validation, lets an attacker on the network path impersonate hex.pm, repo.hex.pm, a self-hosted repository or a mirror. The attacker receives the API keys, OAuth tokens and repository keys Hex sends, and can alter API responses. Registry signatures and package checksums still prevent changes to registry contents and packages."
                    }
                  ],
                  "value": "Users set cacerts_path to limit which CAs can authenticate Hex\u0027s servers, for example to their organization\u0027s internal CA. Every CA in Hex\u0027s bundled store can still authenticate those servers, so a certificate mis-issued by one of those CAs, or obtained through compromised domain validation, lets an attacker on the network path impersonate hex.pm, repo.hex.pm, a self-hosted repository or a mirror. The attacker receives the API keys, OAuth tokens and repository keys Hex sends, and can alter API responses. Registry signatures and package checksums still prevent changes to registry contents and packages."
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "HIGH",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 5.9,
                "baseSeverity": "MEDIUM",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:A/VC:H/VI:L/VA:N/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "NONE",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "LOW",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-295",
                  "description": "CWE-295 Improper Certificate Validation",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-10-12T15:17:45.545Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "name": "GitHub Advisory",
              "tags": [
                "related",
                "vendor-advisory"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-rw8q-hg7m-cxgr"
            },
            {
              "name": "EEF CNA record for CVE-2026-103503",
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-103503.html"
            },
            {
              "name": "OSV record EEF-CVE-2026-103503",
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-103503"
            },
            {
              "name": "Introducing commit c9b26a4 in hexpm/hex",
              "tags": [
                "related"
              ],
              "url": "https://github.com/hexpm/hex/commit/c9b26a46928bfcd546773571e09c1d05f4cd9fb7"
            },
            {
              "name": "Fix commit 5f5a213 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/5f5a2136c7cf5991b6e8a30d645ca9f8e74b0785"
            },
            {
              "name": "Fix commit 6232a64 in hexpm/hex",
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/6232a6498015e559743bec4f4fbec9138837cec8"
            }
          ],
          "solutions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eUpgrade Hex to 2.5.2 or later, for example with \u003ccode\u003emix local.hex\u003c/code\u003e. With \u003ccode\u003ecacerts_path\u003c/code\u003e (\u003ccode\u003eHEX_CACERTS_PATH\u003c/code\u003e) set, Hex then only accepts server certificates that chain to a CA in that file, and it doesn\u0027t trust copies of CA certificates sent by the server.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "Upgrade Hex to 2.5.2 or later, for example with `mix local.hex`. With `cacerts_path` (`HEX_CACERTS_PATH`) set, Hex then only accepts server certificates that chain to a CA in that file, and it doesn\u0027t trust copies of CA certificates sent by the server."
                }
              ],
              "value": "Upgrade Hex to 2.5.2 or later, for example with mix local.hex. With cacerts_path (HEX_CACERTS_PATH) set, Hex then only accepts server certificates that chain to a CA in that file, and it doesn\u0027t trust copies of CA certificates sent by the server."
            }
          ],
          "source": {
            "discovery": "UNKNOWN"
          },
          "title": "Hex trusts its bundled CA certificates when cacerts_path is set",
          "workarounds": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003cp\u003eThere\u0027s no Hex configuration that stops the bundled CAs from being trusted.\u003c/p\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "There\u0027s no Hex configuration that stops the bundled CAs from being trusted."
                }
              ],
              "value": "There\u0027s no Hex configuration that stops the bundled CAs from being trusted."
            }
          ],
          "x_proofOfConcept": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003eCreate a PEM file that contains only an unrelated test CA certificate and set \u003ccode\u003ecacerts_path\u003c/code\u003e to it.\u003c/li\u003e\n\u003cli\u003eOpen a TLS connection to hex.pm with the options from \u003ccode\u003eHex.HTTP.SSL.ssl_opts(\"https://hex.pm\")\u003c/code\u003e. The handshake succeeds, and the accepted chain leads to ISRG Root X2 cross-signed by ISRG Root X1, neither of which is in the PEM file.\u003c/li\u003e\n\u003cli\u003eRemove the \u003ccode\u003epartial_chain\u003c/code\u003e option and connect again. The handshake fails with \u003ccode\u003eunknown_ca\u003c/code\u003e.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. Create a PEM file that contains only an unrelated test CA certificate and set `cacerts_path` to it.\n2. Open a TLS connection to hex.pm with the options from `Hex.HTTP.SSL.ssl_opts(\"https://hex.pm\")`. The handshake succeeds, and the accepted chain leads to ISRG Root X2 cross-signed by ISRG Root X1, neither of which is in the PEM file.\n3. Remove the `partial_chain` option and connect again. The handshake fails with `unknown_ca`."
                }
              ],
              "value": "* Create a PEM file that contains only an unrelated test CA certificate and set cacerts_path to it.\n* Open a TLS connection to hex.pm with the options from Hex.HTTP.SSL.ssl_opts(\"https://hex.pm\"). The handshake succeeds, and the accepted chain leads to ISRG Root X2 cross-signed by ISRG Root X1, neither of which is in the PEM file.\n* Remove the partial_chain option and connect again. The handshake fails with unknown_ca."
            }
          ],
          "x_technicalAnalysis": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "\u003col\u003e\n\u003cli\u003e\u003ccode\u003eHex.HTTP.SSL.get_ca_certs/0\u003c/code\u003e returns the certificates from \u003ccode\u003ecacerts_path\u003c/code\u003e when it\u0027s set, and \u003ccode\u003essl_opts/1\u003c/code\u003e passes them as \u003ccode\u003ecacerts\u003c/code\u003e.\u003c/li\u003e\n\u003cli\u003e\u003ccode\u003essl_opts/1\u003c/code\u003e sets \u003ccode\u003epartial_chain\u003c/code\u003e to \u003ccode\u003e\u0026amp;partial_chain(Certs.cacerts(), \u0026amp;1)\u003c/code\u003e, which always uses the bundled store.\u003c/li\u003e\n\u003cli\u003eWhen the server\u0027s chain doesn\u0027t lead to a certificate in \u003ccode\u003ecacerts\u003c/code\u003e, OTP calls \u003ccode\u003epartial_chain\u003c/code\u003e with the chain. \u003ccode\u003epartial_chain/2\u003c/code\u003e returns \u003ccode\u003e{:trusted_ca, der}\u003c/code\u003e for the first certificate whose public key matches a bundled CA certificate, and OTP validates the chain with that certificate as the trust anchor.\u003c/li\u003e\n\u003cli\u003eChain validation and the hostname check from \u003ccode\u003ecustomize_hostname_check/1\u003c/code\u003e still run, so the attacker needs a certificate for the requested host that chains to a bundled CA.\u003c/li\u003e\n\u003c/ol\u003e"
                },
                {
                  "base64": false,
                  "type": "text/markdown",
                  "value": "1. `Hex.HTTP.SSL.get_ca_certs/0` returns the certificates from `cacerts_path` when it\u0027s set, and `ssl_opts/1` passes them as `cacerts`.\n2. `ssl_opts/1` sets `partial_chain` to `\u0026partial_chain(Certs.cacerts(), \u00261)`, which always uses the bundled store.\n3. When the server\u0027s chain doesn\u0027t lead to a certificate in `cacerts`, OTP calls `partial_chain` with the chain. `partial_chain/2` returns `{:trusted_ca, der}` for the first certificate whose public key matches a bundled CA certificate, and OTP validates the chain with that certificate as the trust anchor.\n4. Chain validation and the hostname check from `customize_hostname_check/1` still run, so the attacker needs a certificate for the requested host that chains to a bundled CA."
                }
              ],
              "value": "* Hex.HTTP.SSL.get_ca_certs/0 returns the certificates from cacerts_path when it\u0027s set, and ssl_opts/1 passes them as cacerts.\n* ssl_opts/1 sets partial_chain to \u0026partial_chain(Certs.cacerts(), \u00261), which always uses the bundled store.\n* When the server\u0027s chain doesn\u0027t lead to a certificate in cacerts, OTP calls partial_chain with the chain. partial_chain/2 returns {:trusted_ca, der} for the first certificate whose public key matches a bundled CA certificate, and OTP validates the chain with that certificate as the trust anchor.\n* Chain validation and the hostname check from customize_hostname_check/1 still run, so the attacker needs a certificate for the requested host that chains to a bundled CA."
            }
          ]
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-103503",
        "datePublished": "2026-10-12T15:17:45.545Z",
        "dateReserved": "2026-10-08T15:45:02.372Z",
        "dateUpdated": "2026-10-12T15:17:45.545Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-32148 (GCVE-0-2026-32148)

    Vulnerability from cvelistv5 – Published: 2026-04-30 18:17 – Updated: 2026-05-01 04:33
    VLAI
    Title
    Lockfile checksums not verified in Hex allows dependency integrity bypass
    Summary
    Insufficient Verification of Data Authenticity vulnerability in hexpm hex (Hex.RemoteConverger module) allows dependency integrity bypass via unverified lockfile checksums. Hex stores checksums for dependencies in the mix.lock file to ensure reproducible and integrity-checked builds. However, Hex.RemoteConverger.verify_resolved/2 never executes checksum verification because the lock data returned by Hex.Utils.lock/1 uses string-based dependency names, while the verification logic compares against atom-based names. This type mismatch causes the verification code path to be silently skipped. Checksums are still validated when packages are initially downloaded from the registry, but mismatches between the lockfile and resolved dependencies are not detected. An attacker who can influence cached packages (e.g., via local cache poisoning or a compromised registry) can provide modified dependency contents that will be accepted without detection. The mix.lock file is silently rewritten with the checksum values from the registry, erasing evidence of tampering. This issue affects hex: from 0.16.0 before 2.4.2.
    SSVC
    Exploitation: poc Automatable: no Technical Impact: total
    CISA Coordinator · CISA-ADP (v2.0.3)
    Decision recorded 2026-04-30 19:03 UTC
    CWE
    • CWE-354 - Improper Validation of Integrity Check Value
    • CWE-494 - Download of Code Without Integrity Check
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex Affected: 0.16.0 , < 2.4.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: e01576f28c64af9fae6eb17e2dad30f6efcb303c , < d7528c8199a1144511508bf3a6460026a5a14c8e (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-32148",
                    "options": [
                      {
                        "Exploitation": "poc"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "total"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-04-30T19:03:06.385106Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-04-30T19:03:24.858Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "references": [
              {
                "tags": [
                  "exploit"
                ],
                "url": "https://github.com/hexpm/hex/security/advisories/GHSA-hmv9-4mfr-m92v"
              }
            ],
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex\u0026vcs_url=git%20https:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:verify_resolved/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.4.2",
                  "status": "affected",
                  "version": "0.16.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "\u0027Elixir.Hex.RemoteConverger\u0027"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "lib/hex/remote_converger.ex"
              ],
              "programRoutines": [
                {
                  "name": "\u0027Elixir.Hex.RemoteConverger\u0027:verify_resolved/2"
                }
              ],
              "repo": "https://github.com/hexpm/hex.git",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "d7528c8199a1144511508bf3a6460026a5a14c8e",
                  "status": "affected",
                  "version": "e01576f28c64af9fae6eb17e2dad30f6efcb303c",
                  "versionType": "git"
                }
              ]
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.4.2",
                      "versionStartIncluding": "0.16.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "OR"
                }
              ],
              "operator": "AND"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Paul Fleischer"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Jonatan M\u00e4nnchen / EEF"
            },
            {
              "lang": "en",
              "type": "remediation reviewer",
              "value": "Eric Meadows-J\u00f6nsson / Hex.pm"
            }
          ],
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "Insufficient Verification of Data Authenticity vulnerability in hexpm hex (\u003ctt\u003eHex.RemoteConverger\u003c/tt\u003e module) allows dependency integrity bypass via unverified lockfile checksums.\u003cp\u003eHex stores checksums for dependencies in the \u003ctt\u003emix.lock\u003c/tt\u003e file to ensure reproducible and integrity-checked builds. However, \u003ctt\u003eHex.RemoteConverger.verify_resolved/2\u003c/tt\u003e never executes checksum verification because the lock data returned by \u003ctt\u003eHex.Utils.lock/1\u003c/tt\u003e uses string-based dependency names, while the verification logic compares against atom-based names. This type mismatch causes the verification code path to be silently skipped. Checksums are still validated when packages are initially downloaded from the registry, but mismatches between the lockfile and resolved dependencies are not detected.\u003c/p\u003e\u003cp\u003eAn attacker who can influence cached packages (e.g., via local cache poisoning or a compromised registry) can provide modified dependency contents that will be accepted without detection. The \u003ctt\u003emix.lock\u003c/tt\u003e file is silently rewritten with the checksum values from the registry, erasing evidence of tampering.\u003c/p\u003e\u003cp\u003eThis issue affects hex: from 0.16.0 before 2.4.2.\u003c/p\u003e"
                }
              ],
              "value": "Insufficient Verification of Data Authenticity vulnerability in hexpm hex (Hex.RemoteConverger module) allows dependency integrity bypass via unverified lockfile checksums.\n\nHex stores checksums for dependencies in the mix.lock file to ensure reproducible and integrity-checked builds. However, Hex.RemoteConverger.verify_resolved/2 never executes checksum verification because the lock data returned by Hex.Utils.lock/1 uses string-based dependency names, while the verification logic compares against atom-based names. This type mismatch causes the verification code path to be silently skipped. Checksums are still validated when packages are initially downloaded from the registry, but mismatches between the lockfile and resolved dependencies are not detected.\n\nAn attacker who can influence cached packages (e.g., via local cache poisoning or a compromised registry) can provide modified dependency contents that will be accepted without detection. The mix.lock file is silently rewritten with the checksum values from the registry, erasing evidence of tampering.\n\nThis issue affects hex: from 0.16.0 before 2.4.2."
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 8.9,
                "baseSeverity": "HIGH",
                "exploitMaturity": "NOT_DEFINED",
                "privilegesRequired": "NONE",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "HIGH",
                "subConfidentialityImpact": "HIGH",
                "subIntegrityImpact": "HIGH",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:A/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
                "version": "4.0",
                "vulnAvailabilityImpact": "HIGH",
                "vulnConfidentialityImpact": "HIGH",
                "vulnIntegrityImpact": "HIGH",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-354",
                  "description": "CWE-354 Improper Validation of Integrity Check Value",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            },
            {
              "descriptions": [
                {
                  "cweId": "CWE-494",
                  "description": "CWE-494 Download of Code Without Integrity Check",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-05-01T04:33:38.198Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "tags": [
                "vendor-advisory",
                "related"
              ],
              "url": "https://github.com/hexpm/hex/security/advisories/GHSA-hmv9-4mfr-m92v"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-32148.html"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-32148"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/d7528c8199a1144511508bf3a6460026a5a14c8e"
            }
          ],
          "source": {
            "discovery": "EXTERNAL"
          },
          "title": "Lockfile checksums not verified in Hex allows dependency integrity bypass",
          "x_generator": {
            "engine": "cvelib 1.8.0"
          }
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-32148",
        "datePublished": "2026-04-30T18:17:03.783Z",
        "dateReserved": "2026-03-10T22:37:29.213Z",
        "dateUpdated": "2026-05-01T04:33:38.198Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }

    CVE-2026-21619 (GCVE-0-2026-21619)

    Vulnerability from cvelistv5 – Published: 2026-02-27 17:57 – Updated: 2026-05-27 15:40
    VLAI
    Title
    Unsafe Deserialization of Erlang Terms in hex_core
    Summary
    Uncontrolled Resource Consumption, Deserialization of Untrusted Data vulnerability in hexpm hex_core (hex_api modules), hexpm hex (mix_hex_api modules), erlang rebar3 (r3_hex_api modules) allows Object Injection, Excessive Allocation. This vulnerability is associated with program files src/hex_api.erl, src/mix_hex_api.erl, apps/rebar/src/vendored/r3_hex_api.erl and program routines hex_core:request/4, mix_hex_api:request/4, r3_hex_api:request/4. This issue affects hex_core: from 0.1.0 before 0.12.1; hex: from 2.3.0 before 2.3.2; rebar3: from 3.9.1 before 3.27.0.
    SSVC
    Exploitation: none Automatable: no Technical Impact: partial
    CISA Coordinator · CISA-ADP (v2.0.3)
    Decision recorded 2026-02-27 19:08 UTC
    CWE
    • CWE-400 - Uncontrolled Resource Consumption
    • CWE-502 - Deserialization of Untrusted Data
    Assigner
    EEF CNA under the mitre root
    CNA scorecard A 97/100 over 314 records in the last 180 days details
    Impacted products
    Vendor Product Version
    hexpm hex_core Affected: eb327f8edfe45507351e38cc0805aa12fa647f0b , < cdf726095bca85ad2549d146df1e831ae93c2b13 (git)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex_core Affected: 0.1.0 , < 0.12.1 (semver)
        cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 314546ac432229518714cc8e3336e916b9da6305 , < 636739f3322514e9303ca335fb630696fcbb3c95 (git)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    hexpm hex Affected: 2.3.0 , < 2.3.2 (semver)
        cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 209c02ec57c2cc3207ee0174c3af3675b8dc8f79 , < 1d4478f527e373de0b225951e53115450e0d9b9d (git)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    erlang rebar3 Affected: 3.9.1 , < 3.27.0 (semver)
        cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*
    Create a notification for this product.
    Show details on NVD website

    {
      "containers": {
        "adp": [
          {
            "metrics": [
              {
                "other": {
                  "content": {
                    "id": "CVE-2026-21619",
                    "options": [
                      {
                        "Exploitation": "none"
                      },
                      {
                        "Automatable": "no"
                      },
                      {
                        "Technical Impact": "partial"
                      }
                    ],
                    "role": "CISA Coordinator",
                    "timestamp": "2026-02-27T19:08:49.652728Z",
                    "version": "2.0.3"
                  },
                  "type": "ssvc"
                }
              }
            ],
            "providerMetadata": {
              "dateUpdated": "2026-02-27T19:08:57.019Z",
              "orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
              "shortName": "CISA-ADP"
            },
            "title": "CISA ADP Vulnrichment"
          }
        ],
        "cna": {
          "affected": [
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_api"
              ],
              "packageName": "hexpm/hex_core",
              "packageURL": "pkg:github/hexpm/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_core:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "cdf726095bca85ad2549d146df1e831ae93c2b13",
                  "status": "affected",
                  "version": "eb327f8edfe45507351e38cc0805aa12fa647f0b",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://repo.hex.pm",
              "cpes": [
                "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "hex_api"
              ],
              "packageName": "hex_core",
              "packageURL": "pkg:hex/hex_core",
              "product": "hex_core",
              "programFiles": [
                "src/hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "hex_core:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex_core",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "0.12.1",
                  "status": "affected",
                  "version": "0.1.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_api"
              ],
              "packageName": "hexpm/hex",
              "packageURL": "pkg:github/hexpm/hex",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "636739f3322514e9303ca335fb630696fcbb3c95",
                  "status": "affected",
                  "version": "314546ac432229518714cc8e3336e916b9da6305",
                  "versionType": "git"
                }
              ]
            },
            {
              "cpes": [
                "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "mix_hex_api"
              ],
              "packageName": "hex",
              "packageURL": "pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex.git\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Fhexpm%2Fhex.git",
              "product": "hex",
              "programFiles": [
                "src/mix_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "mix_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/hexpm/hex",
              "vendor": "hexpm",
              "versions": [
                {
                  "lessThan": "2.3.2",
                  "status": "affected",
                  "version": "2.3.0",
                  "versionType": "semver"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_api"
              ],
              "packageName": "erlang/rebar3",
              "packageURL": "pkg:github/erlang/rebar3",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "1d4478f527e373de0b225951e53115450e0d9b9d",
                  "status": "affected",
                  "version": "209c02ec57c2cc3207ee0174c3af3675b8dc8f79",
                  "versionType": "git"
                }
              ]
            },
            {
              "collectionURL": "https://github.com",
              "cpes": [
                "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*"
              ],
              "defaultStatus": "unaffected",
              "modules": [
                "r3_hex_api"
              ],
              "packageName": "rebar3",
              "packageURL": "pkg:otp/rebar3?repository_url=https:%2F%2Fgithub.com%2Ferlang%2Frebar3.git\u0026vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Ferlang%2Frebar3.git",
              "product": "rebar3",
              "programFiles": [
                "apps/rebar/src/vendored/r3_hex_api.erl"
              ],
              "programRoutines": [
                {
                  "name": "r3_hex_api:request/4"
                }
              ],
              "repo": "https://github.com/erlang/rebar3",
              "vendor": "erlang",
              "versions": [
                {
                  "lessThan": "3.27.0",
                  "status": "affected",
                  "version": "3.9.1",
                  "versionType": "semver"
                }
              ]
            }
          ],
          "cpeApplicability": [
            {
              "nodes": [
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex_core:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "0.12.1",
                      "versionStartIncluding": "0.1.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "AND"
                },
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "2.3.2",
                      "versionStartIncluding": "2.3.0",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "AND"
                },
                {
                  "cpeMatch": [
                    {
                      "criteria": "cpe:2.3:a:erlang:rebar3:*:*:*:*:*:*:*:*",
                      "versionEndExcluding": "3.27.0",
                      "versionStartIncluding": "3.9.1",
                      "vulnerable": true
                    }
                  ],
                  "negate": false,
                  "operator": "AND"
                }
              ],
              "operator": "OR"
            }
          ],
          "credits": [
            {
              "lang": "en",
              "type": "finder",
              "value": "Michael Lubas / Paraxial.io"
            },
            {
              "lang": "en",
              "type": "remediation developer",
              "value": "Jonatan M\u00e4nnchen / EEF"
            },
            {
              "lang": "en",
              "type": "remediation reviewer",
              "value": "Eric Meadows-J\u00f6nsson / Hex.pm"
            }
          ],
          "descriptions": [
            {
              "lang": "en",
              "supportingMedia": [
                {
                  "base64": false,
                  "type": "text/html",
                  "value": "Uncontrolled Resource Consumption, Deserialization of Untrusted Data vulnerability in hexpm hex_core (hex_api modules), hexpm hex (mix_hex_api modules), erlang rebar3 (r3_hex_api modules) allows Object Injection, Excessive Allocation.\u003cp\u003e This vulnerability is associated with program files \u003ctt\u003esrc/hex_api.erl\u003c/tt\u003e, \u003ctt\u003esrc/mix_hex_api.erl\u003c/tt\u003e, \u003ctt\u003eapps/rebar/src/vendored/r3_hex_api.erl\u003c/tt\u003e and program routines \u003ctt\u003ehex_core:request/4\u003c/tt\u003e, \u003ctt\u003emix_hex_api:request/4\u003c/tt\u003e, \u003ctt\u003er3_hex_api:request/4\u003c/tt\u003e.\u003c/p\u003e\u003cp\u003eThis issue affects hex_core: from 0.1.0 before 0.12.1; hex: from 2.3.0 before 2.3.2; rebar3: from 3.9.1 before 3.27.0.\u003c/p\u003e"
                }
              ],
              "value": "Uncontrolled Resource Consumption, Deserialization of Untrusted Data vulnerability in hexpm hex_core (hex_api modules), hexpm hex (mix_hex_api modules), erlang rebar3 (r3_hex_api modules) allows Object Injection, Excessive Allocation. This vulnerability is associated with program files src/hex_api.erl, src/mix_hex_api.erl, apps/rebar/src/vendored/r3_hex_api.erl and program routines hex_core:request/4, mix_hex_api:request/4, r3_hex_api:request/4.\n\nThis issue affects hex_core: from 0.1.0 before 0.12.1; hex: from 2.3.0 before 2.3.2; rebar3: from 3.9.1 before 3.27.0."
            }
          ],
          "impacts": [
            {
              "capecId": "CAPEC-586",
              "descriptions": [
                {
                  "lang": "en",
                  "value": "CAPEC-586 Object Injection"
                }
              ]
            },
            {
              "capecId": "CAPEC-130",
              "descriptions": [
                {
                  "lang": "en",
                  "value": "CAPEC-130 Excessive Allocation"
                }
              ]
            }
          ],
          "metrics": [
            {
              "cvssV4_0": {
                "Automatable": "NOT_DEFINED",
                "Recovery": "NOT_DEFINED",
                "Safety": "NOT_DEFINED",
                "attackComplexity": "LOW",
                "attackRequirements": "PRESENT",
                "attackVector": "NETWORK",
                "baseScore": 2,
                "baseSeverity": "LOW",
                "exploitMaturity": "NOT_DEFINED",
                "privilegesRequired": "LOW",
                "providerUrgency": "NOT_DEFINED",
                "subAvailabilityImpact": "NONE",
                "subConfidentialityImpact": "NONE",
                "subIntegrityImpact": "NONE",
                "userInteraction": "ACTIVE",
                "valueDensity": "NOT_DEFINED",
                "vectorString": "CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:A/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
                "version": "4.0",
                "vulnAvailabilityImpact": "LOW",
                "vulnConfidentialityImpact": "NONE",
                "vulnIntegrityImpact": "NONE",
                "vulnerabilityResponseEffort": "NOT_DEFINED"
              },
              "format": "CVSS",
              "scenarios": [
                {
                  "lang": "en",
                  "value": "GENERAL"
                }
              ]
            }
          ],
          "problemTypes": [
            {
              "descriptions": [
                {
                  "cweId": "CWE-400",
                  "description": "CWE-400 Uncontrolled Resource Consumption",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            },
            {
              "descriptions": [
                {
                  "cweId": "CWE-502",
                  "description": "CWE-502 Deserialization of Untrusted Data",
                  "lang": "en",
                  "type": "CWE"
                }
              ]
            }
          ],
          "providerMetadata": {
            "dateUpdated": "2026-05-27T15:40:33.166Z",
            "orgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
            "shortName": "EEF"
          },
          "references": [
            {
              "tags": [
                "vendor-advisory",
                "related"
              ],
              "url": "https://github.com/hexpm/hex_core/security/advisories/GHSA-hx9w-f2w9-9g96"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://cna.erlef.org/cves/CVE-2026-21619.html"
            },
            {
              "tags": [
                "related"
              ],
              "url": "https://osv.dev/vulnerability/EEF-CVE-2026-21619"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex_core/commit/cdf726095bca85ad2549d146df1e831ae93c2b13"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/hexpm/hex/commit/636739f3322514e9303ca335fb630696fcbb3c95"
            },
            {
              "tags": [
                "patch"
              ],
              "url": "https://github.com/erlang/rebar3/commit/1d4478f527e373de0b225951e53115450e0d9b9d"
            }
          ],
          "source": {
            "discovery": "INTERNAL"
          },
          "title": "Unsafe Deserialization of Erlang Terms in hex_core",
          "x_generator": {
            "engine": "Vulnogram 0.5.0"
          }
        }
      },
      "cveMetadata": {
        "assignerOrgId": "6b3ad84c-e1a6-4bf7-a703-f496b71e49db",
        "assignerShortName": "EEF",
        "cveId": "CVE-2026-21619",
        "datePublished": "2026-02-27T17:57:11.513Z",
        "dateReserved": "2026-01-01T03:46:45.933Z",
        "dateUpdated": "2026-05-27T15:40:33.166Z",
        "state": "PUBLISHED"
      },
      "dataType": "CVE_RECORD",
      "dataVersion": "5.2"
    }