{"containers":{"cna":{"affected":[{"cpes":["cpe:2.3:a:hexpm:hex:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.Mix.Tasks.Hex.Package'","'Elixir.Hex.SCM'"],"packageName":"hex","packageURL":"pkg:otp/hex?repository_url=https:%2F%2Fgithub.com%2Fhexpm%2Fhex&vcs_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":"'Elixir.Mix.Tasks.Hex.Package':run/1"},{"name":"'Elixir.Hex.SCM':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":["'Elixir.Mix.Tasks.Hex.Package'","'Elixir.Hex.SCM'"],"packageName":"hexpm/hex","packageURL":"pkg:github/hexpm/hex","product":"hex","programFiles":["lib/mix/tasks/hex.package.ex","lib/hex/scm.ex"],"programRoutines":[{"name":"'Elixir.Mix.Tasks.Hex.Package':run/1"},{"name":"'Elixir.Hex.SCM':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":"<p>Affects <code>mix hex.package fetch</code> with <code>--output -</code> when packages are downloaded through a mirror set with <code>HEX_MIRROR_URL</code> or <code>mirror_url</code>. Downloads directly from the repository over HTTPS aren't affected unless TLS verification is broken.</p>"},{"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't 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't 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önsson"},{"lang":"en","type":"analyst","value":"Jonatan Männchen / EEF"}],"dateAssigned":"2026-10-10T13:01:30.000Z","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>Improper Validation of Integrity Check Value vulnerability in hexpm hex allows a package mirror to substitute the tarball that <code>mix hex.package fetch PACKAGE VERSION --output -</code> writes to standard output.</p>\n<p>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 <code>mix hex.package fetch</code> writes the bytes returned by <code>Hex.SCM.fetch/3</code> without that comparison, and <code>Hex.SCM.fetch/3</code> doesn't verify freshly downloaded tarballs itself. When a mirror configured with <code>HEX_MIRROR_URL</code> or <code>mirror_url</code> serves altered bytes, the command prints them and exits successfully, while the same fetch with <code>--output FILE</code> fails with a checksum mismatch.</p>\n<p>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 <code>x-hex-message</code> 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.</p>\n<p>This issue affects hex: from 0.20.2 before 2.5.2.</p>"},{"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'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.\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's 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'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.\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's 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":"<p>Hex treats mirrors as untrusted and relies on registry signatures and checksums for package integrity. Scripts that pipe <code>mix hex.package fetch --output -</code> 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.</p>"},{"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":"<p>Upgrade Hex to 2.5.2 or later, for example with <code>mix local.hex</code>. <code>mix hex.package fetch PACKAGE VERSION --output -</code> then verifies the registry checksum before writing the tarball to standard output and prints its messages to standard error.</p>"},{"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":"<p>Write the tarball to a file with <code>--output FILE</code>, which verifies the checksums, and read that file instead of standard output.</p>"},{"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":"<ol>\n<li>Set <code>HEX_MIRROR_URL</code> to a server that returns modified bytes for <code>tarballs/decimal-2.4.1.tar</code> and proxies everything else to repo.hex.pm.</li>\n<li><code>mix hex.package fetch decimal 2.4.1 --output -</code> prints the modified bytes and exits 0.</li>\n<li><code>mix hex.package fetch decimal 2.4.1 --output decimal.tar</code> fails with <code>Checksum mismatch against registry (outer)</code>.</li>\n</ol>"},{"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":"<ol>\n<li><code>mix hex.package fetch PACKAGE VERSION --output -</code> calls <code>fetch_tarball!/3</code>, which calls <code>Hex.SCM.fetch/3</code>.</li>\n<li>For a fresh download, <code>Hex.SCM.fetch/3</code> writes the response body to the cache and returns it without comparing it to the registry checksum.</li>\n<li>The standard output branch passes those bytes to <code>IO.binwrite/1</code>. The file and <code>--unpack</code> branches call <code>verify_inner_checksum!/4</code> and <code>verify_outer_checksum!/4</code> first.</li>\n<li>While the task runs, Hex prints messages with <code>Hex.Shell.info/1</code>, which writes to standard output. <code>Hex.Utils.print_error_result/1</code> prints the body of an error response that way; the update checker calls it when its request for <code>installs/hex-1.x.csv</code> fails, and <code>Hex.Registry.Server</code> calls it when a registry fetch fails and the cached registry is used. <code>Hex.HTTP</code> prints the <code>x-hex-message</code> 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.</li>\n</ol>"},{"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"}