{"api_version":"1","generated_at":"2026-10-30T10:49:35+00:00","cve":"CVE-2026-97209","urls":{"html":"https://cve.report/CVE-2026-97209","api":"https://cve.report/api/cve/CVE-2026-97209.json","docs":"https://cve.report/api","cve_org":"https://www.cve.org/CVERecord?id=CVE-2026-97209","nvd":"https://nvd.nist.gov/vuln/detail/CVE-2026-97209"},"summary":{"title":"Insecure temporary file in mix deps.partition lets a local user execute code in another user's dependency build","description":"Insecure Temporary File vulnerability in Mix deps.partition in Elixir allows a local user to execute code as another user via a swapped partition config file. Partitioned dependency compilation passes the project configuration to each partition VM through a file in a fixed-name directory under the shared system temporary directory, and the partition trusts what it reads back. Another local user on the same host can exploit this during a mix deps.compile run that uses partitioned compilation.\n\nMix.Tasks.Deps.Partition.server/4 in lib/mix/lib/mix/tasks/deps.partition.ex creates the directory with File.mkdir_p/1, which accepts an existing directory without checking its owner, so a user who created it first can replace the file before client/0 reads it.\n\nThis issue affects mix: from 1.20.0-rc.4 before 1.20.5.","state":"PUBLISHED","assigner":"EEF","published_at":"2026-10-30 09:17:15","updated_at":"2026-10-30 09:17:15"},"problem_types":["CWE-377","CWE-377 CWE-377 Insecure Temporary File"],"metrics":[{"version":"4.0","source":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","type":"Secondary","score":"5.4","severity":"MEDIUM","vector":"CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","data":{"version":"4.0","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","baseScore":5.4,"baseSeverity":"MEDIUM","attackVector":"LOCAL","attackComplexity":"LOW","attackRequirements":"PRESENT","privilegesRequired":"LOW","userInteraction":"PASSIVE","vulnConfidentialityImpact":"HIGH","vulnIntegrityImpact":"HIGH","vulnAvailabilityImpact":"HIGH","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","subAvailabilityImpact":"NONE","exploitMaturity":"NOT_DEFINED","confidentialityRequirement":"NOT_DEFINED","integrityRequirement":"NOT_DEFINED","availabilityRequirement":"NOT_DEFINED","modifiedAttackVector":"NOT_DEFINED","modifiedAttackComplexity":"NOT_DEFINED","modifiedAttackRequirements":"NOT_DEFINED","modifiedPrivilegesRequired":"NOT_DEFINED","modifiedUserInteraction":"NOT_DEFINED","modifiedVulnConfidentialityImpact":"NOT_DEFINED","modifiedVulnIntegrityImpact":"NOT_DEFINED","modifiedVulnAvailabilityImpact":"NOT_DEFINED","modifiedSubConfidentialityImpact":"NOT_DEFINED","modifiedSubIntegrityImpact":"NOT_DEFINED","modifiedSubAvailabilityImpact":"NOT_DEFINED","Safety":"NOT_DEFINED","Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","valueDensity":"NOT_DEFINED","vulnerabilityResponseEffort":"NOT_DEFINED","providerUrgency":"NOT_DEFINED"}},{"version":"4.0","source":"CNA","type":"CVSS","score":"5.4","severity":"MEDIUM","vector":"CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","data":{"Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","Safety":"NOT_DEFINED","attackComplexity":"LOW","attackRequirements":"PRESENT","attackVector":"LOCAL","baseScore":5.4,"baseSeverity":"MEDIUM","privilegesRequired":"LOW","providerUrgency":"NOT_DEFINED","subAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","userInteraction":"PASSIVE","valueDensity":"NOT_DEFINED","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N","version":"4.0","vulnAvailabilityImpact":"HIGH","vulnConfidentialityImpact":"HIGH","vulnIntegrityImpact":"HIGH","vulnerabilityResponseEffort":"NOT_DEFINED"}}],"references":[{"url":"https://github.com/elixir-lang/elixir/commit/7f3d95b60c28ae3026a5c1bf943166391245bfd1","name":"https://github.com/elixir-lang/elixir/commit/7f3d95b60c28ae3026a5c1bf943166391245bfd1","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://github.com/elixir-lang/elixir/commit/9adbe955c8664f4be77d879dd38c003dd39fa777","name":"https://github.com/elixir-lang/elixir/commit/9adbe955c8664f4be77d879dd38c003dd39fa777","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://osv.dev/vulnerability/EEF-CVE-2026-97209","name":"https://osv.dev/vulnerability/EEF-CVE-2026-97209","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://cna.erlef.org/cves/CVE-2026-97209.html","name":"https://cna.erlef.org/cves/CVE-2026-97209.html","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://github.com/elixir-lang/elixir/security/advisories/GHSA-96q6-xhwp-fc8q","name":"https://github.com/elixir-lang/elixir/security/advisories/GHSA-96q6-xhwp-fc8q","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://github.com/elixir-lang/elixir/commit/55eb91220a1de14dc5aa27029d1f45b0f5832b2d","name":"https://github.com/elixir-lang/elixir/commit/55eb91220a1de14dc5aa27029d1f45b0f5832b2d","refsource":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","tags":[],"title":"","mime":"","httpstatus":"","archivestatus":"0"},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-97209","name":"CVE Program record","refsource":"CVE.ORG","tags":["canonical"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-97209","name":"NVD vulnerability detail","refsource":"NVD","tags":["canonical","analysis"]}],"affected":[{"source":"CNA","vendor":"elixir-lang","product":"elixir","version":"affected 1.20.0-rc.4 1.20.5 semver","platforms":[]},{"source":"CNA","vendor":"elixir-lang","product":"elixir","version":"affected 7f3d95b60c28ae3026a5c1bf943166391245bfd1 * git","platforms":[]}],"timeline":[],"solutions":[],"workarounds":[{"source":"CNA","title":"","value":"On a multi-user host, set TMPDIR to a private per-user directory with mode 0700 before running Mix, so that System.tmp_dir/0 resolves to a location other users cannot pre-create or read. Alternatively, keep partitioned compilation disabled by leaving MIX_OS_DEPS_COMPILE_PARTITION_COUNT unset or at 1, which keeps the configuration inside the parent process.","time":"","lang":"en"}],"exploits":[],"credits":[{"source":"CNA","value":"Quinn Wilton","lang":"en"},{"source":"CNA","value":"Quinn Wilton","lang":"en"},{"source":"CNA","value":"José Valim","lang":"en"},{"source":"CNA","value":"Jonatan Männchen / EEF","lang":"en"}],"nvd_cpes":[],"vendor_comments":[],"enrichments":{"kev":null,"epss":null,"legacy_qids":[]},"source_records":{"cve_program":{"containers":{"cna":{"affected":[{"cpes":["cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.Mix.Tasks.Deps.Partition'"],"packageName":"mix","packageURL":"pkg:otp/mix?repository_url=https:%2F%2Fgithub.com%2Felixir-lang%2Felixir&vcs_url=git%2Bhttps:%2F%2Fgithub.com%2Felixir-lang%2Felixir.git","product":"elixir","programFiles":["lib/mix/tasks/deps.partition.ex"],"programRoutines":[{"name":"'Elixir.Mix.Tasks.Deps.Partition':server/3"},{"name":"'Elixir.Mix.Tasks.Deps.Partition':server/4"},{"name":"'Elixir.Mix.Tasks.Deps.Partition':client/0"}],"repo":"https://github.com/elixir-lang/elixir","vendor":"elixir-lang","versions":[{"lessThan":"1.20.5","status":"affected","version":"1.20.0-rc.4","versionType":"semver"}]},{"collectionURL":"https://github.com","cpes":["cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*"],"defaultStatus":"unaffected","modules":["'Elixir.Mix.Tasks.Deps.Partition'"],"packageName":"elixir-lang/elixir","packageURL":"pkg:github/elixir-lang/elixir","product":"elixir","programFiles":["lib/mix/lib/mix/tasks/deps.partition.ex"],"programRoutines":[{"name":"'Elixir.Mix.Tasks.Deps.Partition':server/3"},{"name":"'Elixir.Mix.Tasks.Deps.Partition':server/4"},{"name":"'Elixir.Mix.Tasks.Deps.Partition':client/0"}],"repo":"https://github.com/elixir-lang/elixir","vendor":"elixir-lang","versions":[{"changes":[{"at":"55eb91220a1de14dc5aa27029d1f45b0f5832b2d","status":"unaffected"},{"at":"9adbe955c8664f4be77d879dd38c003dd39fa777","status":"unaffected"}],"lessThan":"*","status":"affected","version":"7f3d95b60c28ae3026a5c1bf943166391245bfd1","versionType":"git"}]}],"configurations":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>The attack requires partitioned dependency compilation, which is off by default and enabled by setting <code>MIX_OS_DEPS_COMPILE_PARTITION_COUNT</code> to a value greater than one, a <code>mix deps.compile</code> run that compiles at least two non-local dependencies, and a system temporary directory shared with other local users, which is the default on Linux when <code>TMPDIR</code> is unset. Platforms with per-user temporary directories, such as macOS and Windows by default, are not affected unless <code>TMPDIR</code> points at a shared location.</p>"},{"base64":false,"type":"text/markdown","value":"The attack requires partitioned dependency compilation, which is off by default and enabled by setting `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` to a value greater than one, a `mix deps.compile` run that compiles at least two non-local dependencies, and a system temporary directory shared with other local users, which is the default on Linux when `TMPDIR` is unset. Platforms with per-user temporary directories, such as macOS and Windows by default, are not affected unless `TMPDIR` points at a shared location."}],"value":"The attack requires partitioned dependency compilation, which is off by default and enabled by setting MIX_OS_DEPS_COMPILE_PARTITION_COUNT to a value greater than one, a mix deps.compile run that compiles at least two non-local dependencies, and a system temporary directory shared with other local users, which is the default on Linux when TMPDIR is unset. Platforms with per-user temporary directories, such as macOS and Windows by default, are not affected unless TMPDIR points at a shared location."}],"cpeApplicability":[{"nodes":[{"cpeMatch":[{"criteria":"cpe:2.3:a:elixir-lang:elixir:*:*:*:*:*:*:*:*","versionEndExcluding":"1.20.5","versionStartIncluding":"1.20.0-rc.4","vulnerable":true}],"negate":false,"operator":"OR"}],"operator":"AND"}],"credits":[{"lang":"en","type":"finder","value":"Quinn Wilton"},{"lang":"en","type":"reporter","value":"Quinn Wilton"},{"lang":"en","type":"remediation developer","value":"José Valim"},{"lang":"en","type":"coordinator","value":"Jonatan Männchen / EEF"}],"dateAssigned":"2026-10-15T10:43:20.000Z","datePublic":"2026-10-30T08:59:17.000Z","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>Insecure Temporary File vulnerability in Mix <code>deps.partition</code> in Elixir allows a local user to execute code as another user via a swapped partition config file. Partitioned dependency compilation passes the project configuration to each partition VM through a file in a fixed-name directory under the shared system temporary directory, and the partition trusts what it reads back. Another local user on the same host can exploit this during a <code>mix deps.compile</code> run that uses partitioned compilation.</p>\n<p><code>Mix.Tasks.Deps.Partition.server/4</code> in <code>lib/mix/lib/mix/tasks/deps.partition.ex</code> creates the directory with <code>File.mkdir_p/1</code>, which accepts an existing directory without checking its owner, so a user who created it first can replace the file before <code>client/0</code> reads it.</p>\n<p>This issue affects mix: from 1.20.0-rc.4 before 1.20.5.</p>"},{"base64":false,"type":"text/markdown","value":"Insecure Temporary File vulnerability in Mix `deps.partition` in Elixir allows a local user to execute code as another user via a swapped partition config file. Partitioned dependency compilation passes the project configuration to each partition VM through a file in a fixed-name directory under the shared system temporary directory, and the partition trusts what it reads back. Another local user on the same host can exploit this during a `mix deps.compile` run that uses partitioned compilation.\n\n`Mix.Tasks.Deps.Partition.server/4` in `lib/mix/lib/mix/tasks/deps.partition.ex` creates the directory with `File.mkdir_p/1`, which accepts an existing directory without checking its owner, so a user who created it first can replace the file before `client/0` reads it.\n\nThis issue affects mix: from 1.20.0-rc.4 before 1.20.5."}],"value":"Insecure Temporary File vulnerability in Mix deps.partition in Elixir allows a local user to execute code as another user via a swapped partition config file. Partitioned dependency compilation passes the project configuration to each partition VM through a file in a fixed-name directory under the shared system temporary directory, and the partition trusts what it reads back. Another local user on the same host can exploit this during a mix deps.compile run that uses partitioned compilation.\n\nMix.Tasks.Deps.Partition.server/4 in lib/mix/lib/mix/tasks/deps.partition.ex creates the directory with File.mkdir_p/1, which accepts an existing directory without checking its owner, so a user who created it first can replace the file before client/0 reads it.\n\nThis issue affects mix: from 1.20.0-rc.4 before 1.20.5."}],"impacts":[{"capecId":"CAPEC-26","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>A local user on a shared host who creates the partition directory before the victim's build replaces the serialized configuration and runs arbitrary shell commands as the developer or CI user whose <code>mix deps.compile</code> uses partitioned compilation.</p>"},{"base64":false,"type":"text/markdown","value":"A local user on a shared host who creates the partition directory before the victim's build replaces the serialized configuration and runs arbitrary shell commands as the developer or CI user whose `mix deps.compile` uses partitioned compilation."}],"value":"A local user on a shared host who creates the partition directory before the victim's build replaces the serialized configuration and runs arbitrary shell commands as the developer or CI user whose mix deps.compile uses partitioned compilation."}]},{"capecId":"CAPEC-155","descriptions":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>Even without pre-creating the directory, the world-readable partition file discloses the project configuration, including <code>Mix.install</code> compile-time config, to other local users while the build runs.</p>"},{"base64":false,"type":"text/markdown","value":"Even without pre-creating the directory, the world-readable partition file discloses the project configuration, including `Mix.install` compile-time config, to other local users while the build runs."}],"value":"Even without pre-creating the directory, the world-readable partition file discloses the project configuration, including Mix.install compile-time config, to other local users while the build runs."}]}],"metrics":[{"cvssV4_0":{"Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","Safety":"NOT_DEFINED","attackComplexity":"LOW","attackRequirements":"PRESENT","attackVector":"LOCAL","baseScore":5.4,"baseSeverity":"MEDIUM","privilegesRequired":"LOW","providerUrgency":"NOT_DEFINED","subAvailabilityImpact":"NONE","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","userInteraction":"PASSIVE","valueDensity":"NOT_DEFINED","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:P/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-377","description":"CWE-377 Insecure Temporary File","lang":"en","type":"CWE"}]}],"providerMetadata":{"dateUpdated":"2026-10-30T09:01:05.212Z","orgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","shortName":"EEF"},"references":[{"name":"Insecure temporary file in mix deps.partition lets a local user execute code in another user's dependency build","tags":["vendor-advisory","related"],"url":"https://github.com/elixir-lang/elixir/security/advisories/GHSA-96q6-xhwp-fc8q"},{"name":"EEF CNA record for CVE-2026-97209","tags":["related"],"url":"https://cna.erlef.org/cves/CVE-2026-97209.html"},{"name":"OSV record EEF-CVE-2026-97209","tags":["related"],"url":"https://osv.dev/vulnerability/EEF-CVE-2026-97209"},{"name":"Introducing commit 7f3d95b in elixir-lang/elixir","tags":["related"],"url":"https://github.com/elixir-lang/elixir/commit/7f3d95b60c28ae3026a5c1bf943166391245bfd1"},{"name":"Fix commit 55eb912 in elixir-lang/elixir","tags":["patch"],"url":"https://github.com/elixir-lang/elixir/commit/55eb91220a1de14dc5aa27029d1f45b0f5832b2d"},{"name":"Fix commit 9adbe95 in elixir-lang/elixir","tags":["patch"],"url":"https://github.com/elixir-lang/elixir/commit/9adbe955c8664f4be77d879dd38c003dd39fa777"}],"source":{"discovery":"EXTERNAL"},"title":"Insecure temporary file in mix deps.partition lets a local user execute code in another user's dependency build","workarounds":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p>On a multi-user host, set <code>TMPDIR</code> to a private per-user directory with mode <code>0700</code> before running Mix, so that <code>System.tmp_dir/0</code> resolves to a location other users cannot pre-create or read. Alternatively, keep partitioned compilation disabled by leaving <code>MIX_OS_DEPS_COMPILE_PARTITION_COUNT</code> unset or at <code>1</code>, which keeps the configuration inside the parent process.</p>"},{"base64":false,"type":"text/markdown","value":"On a multi-user host, set `TMPDIR` to a private per-user directory with mode `0700` before running Mix, so that `System.tmp_dir/0` resolves to a location other users cannot pre-create or read. Alternatively, keep partitioned compilation disabled by leaving `MIX_OS_DEPS_COMPILE_PARTITION_COUNT` unset or at `1`, which keeps the configuration inside the parent process."}],"value":"On a multi-user host, set TMPDIR to a private per-user directory with mode 0700 before running Mix, so that System.tmp_dir/0 resolves to a location other users cannot pre-create or read. Alternatively, keep partitioned compilation disabled by leaving MIX_OS_DEPS_COMPILE_PARTITION_COUNT unset or at 1, which keeps the configuration inside the parent process."}],"x_proofOfConcept":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<ol>\n<li>On a multi-user Linux host where <code>System.tmp_dir()</code> resolves to <code>/tmp</code>, the attacker creates <code>/tmp/mix_deps_partition</code> as their own directory and watches it for new files.</li>\n<li>The victim runs <code>mix deps.compile</code> (directly, or through <code>mix compile</code> or <code>mix test</code>) with <code>MIX_OS_DEPS_COMPILE_PARTITION_COUNT=2</code> on a project with at least two non-local dependencies. <code>File.mkdir_p/1</code> succeeds on the existing directory and the config file is written into it.</li>\n<li>Before the partition VMs boot and read the file, the attacker decodes it, adds a <code>compile:</code> shell command to every dependency in <code>config[:deps]</code>, re-encodes it and writes it back.</li>\n<li>Each partition decodes the attacker's term and <code>deps.compile</code> runs the injected command as the victim user.</li>\n</ol>"},{"base64":false,"type":"text/markdown","value":"1. On a multi-user Linux host where `System.tmp_dir()` resolves to `/tmp`, the attacker creates `/tmp/mix_deps_partition` as their own directory and watches it for new files.\n2. The victim runs `mix deps.compile` (directly, or through `mix compile` or `mix test`) with `MIX_OS_DEPS_COMPILE_PARTITION_COUNT=2` on a project with at least two non-local dependencies. `File.mkdir_p/1` succeeds on the existing directory and the config file is written into it.\n3. Before the partition VMs boot and read the file, the attacker decodes it, adds a `compile:` shell command to every dependency in `config[:deps]`, re-encodes it and writes it back.\n4. Each partition decodes the attacker's term and `deps.compile` runs the injected command as the victim user."}],"value":"* On a multi-user Linux host where System.tmp_dir() resolves to /tmp, the attacker creates /tmp/mix_deps_partition as their own directory and watches it for new files.\n* The victim runs mix deps.compile (directly, or through mix compile or mix test) with MIX_OS_DEPS_COMPILE_PARTITION_COUNT=2 on a project with at least two non-local dependencies. File.mkdir_p/1 succeeds on the existing directory and the config file is written into it.\n* Before the partition VMs boot and read the file, the attacker decodes it, adds a compile: shell command to every dependency in config[:deps], re-encodes it and writes it back.\n* Each partition decodes the attacker's term and deps.compile runs the injected command as the victim user."}],"x_technicalAnalysis":[{"lang":"en","supportingMedia":[{"base64":false,"type":"text/html","value":"<p><strong>1. Payload written to a shared location</strong></p>\n<p><code>Mix.Tasks.Deps.Partition.server/4</code> in <code>lib/mix/lib/mix/tasks/deps.partition.ex</code> encodes <code>Mix.ProjectStack.peek()</code> with <code>:erlang.term_to_binary/1</code> and Base64, calls <code>File.mkdir_p/1</code> on <code>Path.join(System.tmp_dir(), \"mix_deps_partition\")</code>, and writes the payload to a file with a random name inside it. The directory name is fixed, carries no user id, and <code>File.mkdir_p/1</code> succeeds on a directory that already exists, whoever owns it. The file is created with the default mode, so it is readable by other users in a shared temporary directory.</p>\n<p><strong>2. Partition VMs trust the file</strong></p>\n<p>Each partition is a fresh <code>elixir</code> VM started with <code>--config-file &lt;path&gt;</code>. <code>Mix.Tasks.Deps.Partition.client/0</code> reads the file with <code>File.read!/1</code>, decodes it with <code>:erlang.binary_to_term/1</code>, and pushes the decoded entry (project name, config and <code>mix.exs</code> path) with <code>Mix.ProjectStack.push/3</code>. Nothing verifies that the file still holds what the parent wrote.</p>\n<p><strong>3. Attacker control</strong></p>\n<p>A local user who created <code>mix_deps_partition</code> before the victim's build owns it and may replace or rewrite any file inside, so they swap the payload between the parent's write and the client's read. The client then compiles the attacker's <code>deps</code> list, and a dependency's <code>compile:</code> option is a shell command Mix executes in the victim's build. On the development branch the payload also carries <code>code_path</code> and <code>compiler_options</code>, which the client applies with <code>:code.set_path/1</code> and <code>Code.compiler_options/1</code>, so there the attacker also controls the client VM's code path.</p>"},{"base64":false,"type":"text/markdown","value":"**1. Payload written to a shared location**\n\n`Mix.Tasks.Deps.Partition.server/4` in `lib/mix/lib/mix/tasks/deps.partition.ex` encodes `Mix.ProjectStack.peek()` with `:erlang.term_to_binary/1` and Base64, calls `File.mkdir_p/1` on `Path.join(System.tmp_dir(), \"mix_deps_partition\")`, and writes the payload to a file with a random name inside it. The directory name is fixed, carries no user id, and `File.mkdir_p/1` succeeds on a directory that already exists, whoever owns it. The file is created with the default mode, so it is readable by other users in a shared temporary directory.\n\n**2. Partition VMs trust the file**\n\nEach partition is a fresh `elixir` VM started with `--config-file <path>`. `Mix.Tasks.Deps.Partition.client/0` reads the file with `File.read!/1`, decodes it with `:erlang.binary_to_term/1`, and pushes the decoded entry (project name, config and `mix.exs` path) with `Mix.ProjectStack.push/3`. Nothing verifies that the file still holds what the parent wrote.\n\n**3. Attacker control**\n\nA local user who created `mix_deps_partition` before the victim's build owns it and may replace or rewrite any file inside, so they swap the payload between the parent's write and the client's read. The client then compiles the attacker's `deps` list, and a dependency's `compile:` option is a shell command Mix executes in the victim's build. On the development branch the payload also carries `code_path` and `compiler_options`, which the client applies with `:code.set_path/1` and `Code.compiler_options/1`, so there the attacker also controls the client VM's code path."}],"value":"1. Payload written to a shared location\n\nMix.Tasks.Deps.Partition.server/4 in lib/mix/lib/mix/tasks/deps.partition.ex encodes Mix.ProjectStack.peek() with :erlang.term_to_binary/1 and Base64, calls File.mkdir_p/1 on Path.join(System.tmp_dir(), \"mix_deps_partition\"), and writes the payload to a file with a random name inside it. The directory name is fixed, carries no user id, and File.mkdir_p/1 succeeds on a directory that already exists, whoever owns it. The file is created with the default mode, so it is readable by other users in a shared temporary directory.\n\n2. Partition VMs trust the file\n\nEach partition is a fresh elixir VM started with --config-file <path>. Mix.Tasks.Deps.Partition.client/0 reads the file with File.read!/1, decodes it with :erlang.binary_to_term/1, and pushes the decoded entry (project name, config and mix.exs path) with Mix.ProjectStack.push/3. Nothing verifies that the file still holds what the parent wrote.\n\n3. Attacker control\n\nA local user who created mix_deps_partition before the victim's build owns it and may replace or rewrite any file inside, so they swap the payload between the parent's write and the client's read. The client then compiles the attacker's deps list, and a dependency's compile: option is a shell command Mix executes in the victim's build. On the development branch the payload also carries code_path and compiler_options, which the client applies with :code.set_path/1 and Code.compiler_options/1, so there the attacker also controls the client VM's code path."}]}},"cveMetadata":{"assignerOrgId":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","assignerShortName":"EEF","cveId":"CVE-2026-97209","datePublished":"2026-10-30T08:59:17.615Z","dateReserved":"2026-10-14T21:45:01.541Z","dateUpdated":"2026-10-30T09:01:05.212Z","state":"PUBLISHED"},"dataType":"CVE_RECORD","dataVersion":"5.2"},"nvd":{"publishedDate":"2026-10-30 09:17:15","lastModifiedDate":"2026-10-30 09:17:15","problem_types":["CWE-377","CWE-377 CWE-377 Insecure Temporary File"],"metrics":{"cvssMetricV40":[{"source":"6b3ad84c-e1a6-4bf7-a703-f496b71e49db","type":"Secondary","cvssData":{"version":"4.0","vectorString":"CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:P/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","baseScore":5.4,"baseSeverity":"MEDIUM","attackVector":"LOCAL","attackComplexity":"LOW","attackRequirements":"PRESENT","privilegesRequired":"LOW","userInteraction":"PASSIVE","vulnConfidentialityImpact":"HIGH","vulnIntegrityImpact":"HIGH","vulnAvailabilityImpact":"HIGH","subConfidentialityImpact":"NONE","subIntegrityImpact":"NONE","subAvailabilityImpact":"NONE","exploitMaturity":"NOT_DEFINED","confidentialityRequirement":"NOT_DEFINED","integrityRequirement":"NOT_DEFINED","availabilityRequirement":"NOT_DEFINED","modifiedAttackVector":"NOT_DEFINED","modifiedAttackComplexity":"NOT_DEFINED","modifiedAttackRequirements":"NOT_DEFINED","modifiedPrivilegesRequired":"NOT_DEFINED","modifiedUserInteraction":"NOT_DEFINED","modifiedVulnConfidentialityImpact":"NOT_DEFINED","modifiedVulnIntegrityImpact":"NOT_DEFINED","modifiedVulnAvailabilityImpact":"NOT_DEFINED","modifiedSubConfidentialityImpact":"NOT_DEFINED","modifiedSubIntegrityImpact":"NOT_DEFINED","modifiedSubAvailabilityImpact":"NOT_DEFINED","Safety":"NOT_DEFINED","Automatable":"NOT_DEFINED","Recovery":"NOT_DEFINED","valueDensity":"NOT_DEFINED","vulnerabilityResponseEffort":"NOT_DEFINED","providerUrgency":"NOT_DEFINED"}}]},"configurations":[]},"legacy_mitre":{"record":{"CveYear":"2026","CveId":"97209","Ordinal":"1","Title":"Insecure temporary file in mix deps.partition lets a local user ","CVE":"CVE-2026-97209","Year":"2026"},"notes":[{"CveYear":"2026","CveId":"97209","Ordinal":"1","NoteData":"Insecure Temporary File vulnerability in Mix deps.partition in Elixir allows a local user to execute code as another user via a swapped partition config file. Partitioned dependency compilation passes the project configuration to each partition VM through a file in a fixed-name directory under the shared system temporary directory, and the partition trusts what it reads back. Another local user on the same host can exploit this during a mix deps.compile run that uses partitioned compilation.\n\nMix.Tasks.Deps.Partition.server/4 in lib/mix/lib/mix/tasks/deps.partition.ex creates the directory with File.mkdir_p/1, which accepts an existing directory without checking its owner, so a user who created it first can replace the file before client/0 reads it.\n\nThis issue affects mix: from 1.20.0-rc.4 before 1.20.5.","Type":"Description","Title":"Insecure temporary file in mix deps.partition lets a local user "}]}}}