Dependency and Registry Attacks in ML Stacks
Why ML environments are unusually exposed to package-level attacks, the specific techniques that keep working, and the controls that actually reduce exposure.
A machine learning environment typically installs several hundred packages, many transitively, including compiled extensions, CUDA libraries and research code published by individuals. The install runs with the user's privileges and frequently executes setup code. Every property that makes this convenient also makes it exposed.
The techniques
Typosquatting publishes a package whose name resembles a popular one, relying on a mistyped install command. It is trivial to execute and continues to work.
Dependency confusion exploits resolvers that check a public index alongside a private one. Publishing a package to the public index with the same name as an internal package, at a higher version, causes the resolver to prefer the attacker's. This affects organisations with internal packages specifically, and the fix is configuration: scoped indexes, explicit index pinning, or namespace reservation on the public registry.
Account compromise of a legitimate maintainer is the highest-impact variant, because the malicious version arrives from a trusted source with a trusted name. Registry-side two-factor requirements for popular packages exist for this reason.
Install-time execution. A source distribution's build script runs on installation, so compromise happens before any code is imported. Preferring wheels, which do not execute a build script, removes this path for packages that publish them.
Why ML stacks are worse than average
Research code is often installed directly from a repository at a branch rather than from a registry at a pinned version, which means the dependency is whatever the author pushed most recently. Notebooks encourage installing packages interactively, outside any lockfile. Environments are large, so review is impractical and nobody knows the full transitive set. And the compiled and GPU-specific parts of the stack have complex build requirements that push teams toward source installs.
The controls that help
A lockfile with hashes pins the complete resolved graph and makes tampering detectable. This is the highest-value single control.
Wheels over source distributions removes install-time execution for the packages that provide them.
An internal mirror or proxy with an allowlist decouples builds from registry availability and gives a single place to enforce policy, and it also protects against the package that gets yanked mid-release.
Scanning against advisory databases catches known vulnerable versions, which is a different problem from malicious packages and is worth solving too.
Separating environments by privilege. The environment that trains a model does not need production credentials, and the one that serves it does not need the research stack.
When it breaks
Lockfiles do not cover what is not in them. Packages installed inside a notebook, models downloaded at runtime, and datasets fetched from a URL are all dependencies that no lockfile records and no scanner examines.
Vulnerability scanning has a poor signal-to-noise ratio. A large ML environment produces many advisories, most in code paths the application never reaches. Without reachability analysis, teams triage by severity and eventually stop reading, which is the same alert-fatigue failure as elsewhere.
Pinning conflicts with patching. A perfectly pinned environment does not receive security fixes until someone deliberately updates. The reconciliation is the same as for reproducibility: a regular update cadence with tests, and exact pins on released artefacts.
The base image is a dependency too. A CUDA base image contains an operating system with its own packages and its own advisories, and it is usually the largest single source of reported vulnerabilities in an ML container. Choosing a minimal base and rebuilding on a schedule addresses more of the surface than auditing Python packages does.
12 flashcards for this concept
Click a card to reveal the answer.