Elixir and its Phoenix framework now power real-time backends at companies like Discord and Pinterest, plus a growing list of fintech and infrastructure teams, and nearly every one of those systems pulls its dependencies from a single registry: Hex.pm. Hex.pm supply chain security has stayed a relatively quiet topic compared to npm or PyPI, largely because the Elixir ecosystem is smaller and Hex's design already blocks some of the worst attack patterns seen elsewhere. But "quieter" is not the same as "safe." Hex.pm has hosted more than 17,000 packages since launching in 2014, mix.lock files are trusted by default in most CI pipelines, and a single compromised maintainer account or malicious native-code dependency can still reach production. This post looks at how Hex.pm actually works, where Elixir dependency risk concentrates, and what security teams should do about it.
What is Hex.pm and why does hex.pm supply chain security matter?
Hex.pm is the official package manager and registry for the Erlang and Elixir ecosystems, first released in 2014 by Eric Meadows-Jönsson, Wojtek Mach, and the Elixir core team, and later stewarded with funding from Dashbit and the Erlang Ecosystem Foundation. Every mix deps.get in a Phoenix or Elixir project resolves packages through Hex, and the same registry also serves Erlang projects via rebar3. Because Elixir compiles to BEAM bytecode and is increasingly used for payment processing, chat infrastructure, IoT backends, and internal platform tooling, a compromised package doesn't stay contained to a hobby repo — it runs with the same trust level as your application code, inside your build and deploy pipeline. Hex.pm supply chain security matters for the same reason npm and PyPI security started mattering around 2016–2018: once a registry crosses a critical mass of production usage, it becomes a target, and Elixir shops have historically had far less tooling coverage watching their dependency tree than JavaScript or Python teams do.
How does Hex.pm protect against malicious packages by default?
Hex.pm blocks several attack patterns that other registries learned about the hard way. Unlike npm, Hex packages cannot run arbitrary install scripts — there's no postinstall equivalent, because mix deps.get only fetches package tarballs and mix compile runs a compile step defined by your own project, not an arbitrary script bundled by the dependency author. Package versions are also immutable and addressed by a SHA-256 checksum recorded in mix.lock, so once you lock a dependency graph, Hex won't silently swap the bytes behind a given version number. Hex added two-factor authentication for publishers and scoped API tokens years ago, cutting down the account-takeover surface that drove high-profile incidents elsewhere, like the 2021 ua-parser-js and 2022 node-ipc compromises on npm. Hex also handles deletion narrowly: a published version can only be pulled within a short grace window, and never once other packages depend on it — a direct, designed-in answer to the 2016 "left-pad" style breakage that took down builds across npm.
What makes elixir dependency risk different from npm or PyPI?
Elixir dependency risk concentrates less in install-time scripts and more in native compilation and the Erlang layer underneath your app. Many Hex packages that wrap C libraries or Rust NIFs (via Rustler) still execute code at build time through Makefiles or Cargo, and packages using rustler_precompiled fetch precompiled binaries directly from GitHub releases — outside Hex's own checksum guarantees. That means the integrity check you're trusting is Hex's, but the actual compiled binary loaded into your running application came from a separate, less-audited channel. Elixir projects also inherit the entire Erlang/OTP dependency graph underneath the language, so a vulnerability in OTP itself can affect any Elixir service regardless of which Hex packages you personally chose. The clearest recent example is CVE-2025-32433, a maximum-severity (CVSS 10.0) pre-authentication remote code execution flaw in Erlang/OTP's SSH server implementation, disclosed in April 2025 — any Elixir or Erlang service exposing SSH on an unpatched OTP version was vulnerable, independent of anything in mix.lock. And because Hex supports private "organizations" alongside its public registry, teams that mirror internal package names publicly can be exposed to the same dependency-confusion pattern that hit internal npm packages at several large tech companies in 2021.
Has Hex.pm ever had a real hex.pm malicious package incident?
Hex.pm hasn't seen a malicious-package campaign at the scale of npm's event-stream (2018) or PyPI's repeated typosquatting waves, but the ecosystem has most of the same preconditions that made those campaigns possible elsewhere. A small number of widely depended-on packages — phoenix, ecto, plug, jason, guardian — sit at the root of thousands of transitive dependency trees, and a convincingly named typosquat (a single transposed letter, an extra pluralization, a fake "v2" fork) is exactly the kind of thing a rushed mix deps.get copy-paste wouldn't catch. It's worth distinguishing the two failure modes clearly: CVE-2025-32433 is a vulnerability in trusted code, while a malicious package is code intentionally planted to do harm — Hex's no-install-script design meaningfully reduces the blast radius of the latter, but it doesn't eliminate it, since malicious logic can still ship inside a package's actual application code and run the moment it's called at runtime, not at install time. Security researchers who track under-monitored registries increasingly flag Hex as fitting the profile npm did around 2015: fast-growing production adoption paired with comparatively thin automated scanning for typosquats and anomalous publishes.
What should Elixir teams do to reduce hex.pm supply chain security risk today?
Start by treating mix.lock as an audit trail, not a formality — commit it, review diffs on every dependency bump in pull requests, and don't let CI silently regenerate it. Turn on Hex two-factor authentication organization-wide and replace long-lived personal API tokens with scoped, package-specific ones. Audit any dependency that pulls precompiled binaries (Rustler NIFs, rustler_precompiled, C extensions built via Makefiles) since these bypass Hex's own checksum guarantees and deserve the same scrutiny you'd give a vendored binary. Patch Erlang/OTP promptly and track OTP CVEs separately from Hex package CVEs, since they're a different trust boundary entirely — CVE-2025-32433 is a good reminder that "no vulnerable Hex packages" doesn't mean "no vulnerable dependencies." Finally, monitor for typosquats of your organization's most-used packages, and pin exact versions for anything with build-time code execution rather than allowing floating version ranges to silently pull in a newer, unreviewed release.
How Safeguard Helps
Safeguard gives Elixir and Erlang teams the same continuous supply chain visibility that JavaScript and Python teams have had for years, purpose-built for how Hex and Mix actually resolve dependencies. We continuously diff mix.lock changes across every repository, flag new transitive dependencies introduced by version bumps, and surface packages that pull precompiled binaries or shell out to Makefiles at build time — the exact spots where Elixir dependency risk concentrates outside Hex's own guarantees. Safeguard also correlates your dependency graph against known CVEs across both the Hex registry and the underlying Erlang/OTP runtime, so an issue like CVE-2025-32433 gets caught and prioritized even when it has nothing to do with which packages you picked. On top of that, we watch for typosquat registrations and anomalous publish activity targeting the Hex packages your services actually depend on, and enforce policy in CI so a suspicious or unreviewed dependency never quietly reaches production. If you're running Phoenix, Nerves, or any BEAM-based service in production, Safeguard turns hex.pm supply chain security from a blind spot into something your team can actually see, measure, and control.