There is a quiet assumption baked into every build pipeline on earth: that pulling a dependency is a passive act. You ask for a package, the registry hands you some files, and nothing happens until your code imports them. That assumption is wrong, and attackers have spent 2026 proving it at scale.
When you run npm install or pip install, you are not downloading data. You are running someone else's code, on your machine or your CI runner, with your privileges, before a single line of your application executes. The lifecycle hooks that make this possible (postinstall in npm, setup.py and build hooks in Python) were designed for legitimate work like compiling native bindings. They have become the single most reliable way to turn a registry account into remote code execution on thousands of developer laptops and pipelines at once.
Install Is Execution, And That Is the Whole Problem
The mechanics are mundane, which is exactly why they are dangerous. An npm package declares a postinstall script in its package.json, and the package manager dutifully runs it during installation. A Python package puts arbitrary code in setup.py, and pip runs it to build the distribution. No import required, no application logic invoked, no user in the loop. The act of resolving a dependency tree is the act of executing untrusted code.
Microsoft's threat intelligence team documented the canonical chain in a May 2026 campaign that abused dependency confusion against internal corporate namespaces: npm install triggers postinstall, which runs an obfuscated scripts/postinstall.js, which fires an HTTPS request to a command-and-control server, writes a payload to the temp directory, and spawns a detached process. Every step is boring. None of it touches your code. By the time anything looks suspicious, the runner has already phoned home.
Python has the same structural flaw with an extra twist. Beyond setup.py, attackers in 2026 have leaned on a *-setup.pth file processed by Python's site module during interpreter startup. That means the payload can run after installation on the next interpreter launch, without the victim ever importing the poisoned package. As researchers have put it, PyPI's openness combined with automatic code execution at install time is a structural invitation, not a bug to be patched.
The 2026 Campaigns Were Not Subtle About It
This is not theoretical. The year has produced a steady drumbeat of real incidents, and the pattern is consistent enough to be a playbook.
In June 2026, an attacker compromised the @mastra npm organization and quietly added a dependency, easy-day-js, across more than 140 packages. That dependency carried an obfuscated postinstall dropper. Around the same window, a campaign Microsoft documented as Miasma hit at least 32 packages published under the @redhat-cloud-services namespace on June 1, riding the project's own trusted CI/CD publishing pipeline (with authentic provenance) rather than any code review a human would have seen. On the typosquatting front, Microsoft also documented npm packages crafted to steal cloud and CI/CD secrets, which is the real prize: a postinstall running inside a build runner sits next to your registry tokens, cloud credentials, and signing keys.
The Python side rhymes. The Hades campaign poisoned 19 PyPI packages to auto-run a Bun-based credential stealer. The popular lightning package (the deep learning framework formerly shipped as pytorch-lightning) had two malicious releases, versions 2.6.2 and 2.6.3, that hid a _runtime directory which downloaded the Bun JavaScript runtime from GitHub at import time and used it to run a roughly 11 MB obfuscated credential stealer. Reporting through the first half of 2026 also tied install-time and import-time compromises to high-traffic projects in the AI tooling space, where trusted maintainer pipelines were abused to publish a malicious version that exfiltrated credentials.
A few things stand out across all of these. Self-propagation is now table stakes; the Shai-Hulud worm in late 2025 ended the nuisance era, and 2026's worms spread through the same install hooks they exploit. Attackers also keep finding new triggers: the "Phantom Gyp" technique abused a 157-byte binding.gyp file to get code execution during npm install while sidestepping most install-script checks. The attack surface is wider than postinstall alone, but postinstall is the front door.
Why the Old Advice Stopped Working
For years the standard guidance was "pin your versions and watch your dependencies." That is necessary and no longer sufficient. Pinning protects you from a version you did not choose; it does nothing when a maintainer you already trust pushes a poisoned release of a version range you already accepted, or when a transitive dependency five levels deep flips malicious overnight.
Manual review does not scale either. A modern Node project resolves thousands of packages. Nobody is reading every postinstall across that tree on every install, and the payloads are obfuscated specifically to defeat a skim. The honest position is that you cannot trust install-time execution by default, so the defense has to assume the worst and contain it.
What Actually Reduces the Blast Radius
There is no single switch, but there is a stack of controls that compounds. In rough order of impact:
Turn off install scripts by default. Running with --ignore-scripts, or setting ignore-scripts=true globally, is the bluntest and most effective lever. The catch is that it breaks packages with legitimate native builds like better-sqlite3. The surgical version is an allowlist: block scripts globally and explicitly permit the handful of packages that genuinely need them. npm's trustedDependencies field and tools like LavaMoat's allow-scripts exist precisely for this. Worth noting for planning: the npm team published breaking changes for v12 (estimated July 2026) that flip the default so install scripts run for nothing unless you say so. Treat that as a preview, not a fact on the ground, and do not wait for it.
Add a cooldown before adopting fresh releases. Most malicious versions are caught and yanked within days. Refusing to install anything newer than a set window (for example a min-release-age of 30 days) takes you out of the firing line for the riskiest period without much practical cost.
Sandbox the install itself. Run dependency installation in a container with network egress restricted to an internal package proxy and nothing else. If a postinstall cannot reach a C2 server or read your cloud metadata endpoint, it cannot exfiltrate anything, obfuscation or not. This is the control that turns a credential theft into a logged, blocked outbound connection.
Hold the line on lockfile discipline. Commit lockfiles, install from them with npm ci or the equivalent, and review lockfile diffs as carefully as code diffs. A dependency you never intentionally added appearing in the lockfile is exactly the signal the Mastra victims would have wanted.
Vet what you pull, with provenance. Maintainer reputation, release cadence, signing, and build attestation all feed a real risk decision. Provenance and attestation let you verify that a published artifact actually came from the source repository and pipeline it claims to, which is the gap the maintainer-pipeline compromises drove straight through.
How Safeguard Helps
Safeguard treats every dependency as install-time code, not inert data. We generate an SBOM and AIBOM for what you actually ship, flag packages whose install hooks behave suspiciously, and enforce policy gates in CI that fail a build before a poisoned postinstall ever runs in your pipeline. Our Multi-Agent TAOR Deep Think engine cross-checks findings so you are triaging verified supply-chain risk rather than drowning in noise, and the vendor scorecard and provenance checks turn "do we trust this maintainer" into an evidence-backed answer. The platform is model-agnostic, so the orchestration and verification layer stays reliable regardless of which model sits underneath.
If install-time execution is a gap in your pipeline, reach out and we will walk through your dependency surface with you.