CVE-2026-105668 (GCVE-0-2026-105668)
Vulnerability from cvelistv5
Published
2026-10-12 15:31
Modified
2026-10-16 17:38
Severity ?
VLAI Severity ?
EPSS score ?
CWE
- CWE-693 - Protection Mechanism Failure
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.
References
Impacted products
{
"containers": {
"adp": [
{
"metrics": [
{
"other": {
"content": {
"id": "CVE-2026-105668",
"options": [
{
"Exploitation": "none"
},
{
"Automatable": "no"
},
{
"Technical Impact": "total"
}
],
"role": "CISA Coordinator",
"timestamp": "2026-10-16T17:37:56.690913Z",
"version": "2.0.3"
},
"type": "ssvc"
}
}
],
"providerMetadata": {
"dateUpdated": "2026-10-16T17:38:34.235Z",
"orgId": "134c704f-9b21-4f2e-91b3-4a467353bcc0",
"shortName": "CISA-ADP"
},
"title": "CISA ADP Vulnrichment"
}
],
"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-16T17:38:34.235Z",
"state": "PUBLISHED"
},
"dataType": "CVE_RECORD",
"dataVersion": "5.2",
"vulnerability-lookup:meta": {
"vulnrichment": {
"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\": {\"orgId\": \"6b3ad84c-e1a6-4bf7-a703-f496b71e49db\", \"shortName\": \"EEF\", \"dateUpdated\": \"2026-10-12T15:31:58.926Z\"}, \"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.\"}]}, \"adp\": [{\"title\": \"CISA ADP Vulnrichment\", \"metrics\": [{\"other\": {\"type\": \"ssvc\", \"content\": {\"id\": \"CVE-2026-105668\", \"role\": \"CISA Coordinator\", \"options\": [{\"Exploitation\": \"none\"}, {\"Automatable\": \"no\"}, {\"Technical Impact\": \"total\"}], \"version\": \"2.0.3\", \"timestamp\": \"2026-10-16T17:37:56.690913Z\"}}}], \"providerMetadata\": {\"orgId\": \"134c704f-9b21-4f2e-91b3-4a467353bcc0\", \"shortName\": \"CISA-ADP\", \"dateUpdated\": \"2026-10-16T17:38:21.226Z\"}}]}",
"cveMetadata": "{\"cveId\": \"CVE-2026-105668\", \"assignerOrgId\": \"6b3ad84c-e1a6-4bf7-a703-f496b71e49db\", \"state\": \"PUBLISHED\", \"assignerShortName\": \"EEF\", \"dateReserved\": \"2026-10-07T22:15:01.885Z\", \"datePublished\": \"2026-10-12T15:31:58.926Z\", \"dateUpdated\": \"2026-10-16T17:38:34.235Z\"}",
"dataType": "CVE_RECORD",
"dataVersion": "5.2"
}
}
}
Loading…
Loading…
Sightings
| Author | Source | Type | Date |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.
Loading…
Loading…