In 2021, a package called fabrice landed on PyPI — a one-letter typosquat of fabric, the SSH automation library with more than 200 million downloads. Over roughly 37,000 installs before removal, fabrice ran a platform-specific payload that harvested AWS credentials and dropped a persistence binary into hidden paths like ~/.local/bin/vscode, according to reporting from BleepingComputer and Hackread. The attack didn't need a victim to write a single line of code that imported anything suspicious — the theft happened during pip install, before the package was ever used. That pattern has only accelerated: in March 2026, attackers compromised a maintainer account behind LiteLLM and pushed malicious versions carrying an infostealer that targeted AWS, GCP, GitHub tokens, SSH keys, and crypto wallets, exploiting code that auto-executes at interpreter start with no explicit import required (Ox Security, Trend Micro). This post explains why pip install itself is a code-execution event, walks through the real incidents that exploited it, and covers the concrete controls — sandboxing and install-time filtering — that stop it before credentials ever leave the machine.
Why does installing a Python package run arbitrary code before you ever import it?
Because PyPI's source distribution format, the sdist (a .tar.gz archive), can ship a legacy setup.py file, and pip install executes that file directly as part of building the package — not as part of running your application. Security researcher writeups from Embrace The Red and Veracode, along with independent analysis published on Ochrona's Medium blog, all converge on the same point: setup.py supports arbitrary Python, including os.system() calls, network requests, and file writes, and none of it requires an import statement anywhere in your code. This is distinct from the newer wheel (.whl) format, which ships pre-built and doesn't execute build-time code on install. A developer who runs pip install some-package inside a CI job or on a laptop with ~/.aws/credentials present has, in that moment, handed the package author a code-execution primitive with access to every environment variable and credential file the installing user can read.
How did the fabrice and LiteLLM incidents actually exfiltrate credentials?
Both relied on install-time or import-time execution reaching for known credential locations rather than any novel exploit. fabrice's payload branched by OS — separate code paths for Linux and Windows — read AWS credential files, and exfiltrated them off-host while writing a disguised binary to a hidden directory for persistence, per BleepingComputer's and Hackread's writeups. The LiteLLM compromise, tracked by Ox Security and Trend Micro to an attacker identified as "TeamPCP," went further: it didn't rely on a typosquat name at all but hijacked an actual maintainer account to push malicious versions of a legitimately popular package, then used auto-executing code at interpreter startup to sweep AWS, GCP, and GitHub tokens plus SSH keys and crypto wallet files — no explicit import of the malicious module needed by the victim's own code. Both cases show the same underlying lesson: once code runs with a developer's or CI runner's ambient permissions, it can read anything that identity can read.
Are these always genuine external attacks, and how can defenders tell?
Not always — and conflating a controlled exercise with a real compromise leads teams to draw the wrong lessons. In one widely cited 2025 case, JFrog's research team documented chimera-sandbox-extensions, a package impersonating Grab's internal Chimera Sandbox tooling that reached only 143 downloads before it was pulled; it used a domain generation algorithm to reach a command-and-control server and stage a multi-stage credential stealer targeting AWS tokens, CI/CD environment variables, and macOS/Jamf data. CSO Online and The Hacker News later confirmed the campaign was Grab's own internal red-team exercise, not an external breach. The technical mechanism — DGA-based C2, staged payloads, cloud-token harvesting — is still worth studying defensively, but attributing it to a genuine adversary would have been wrong. Before treating any disclosed "attack" as a live threat, check whether the vendor or a named researcher has confirmed it as external.
What newer techniques are attackers using to evade static review of install scripts?
Fetching the actual payload at runtime instead of shipping it in the package, so a one-time static review of the published code never sees what eventually executes. Socket Security's May 2026 research on a campaign it named TrapDoor found 34 packages spanning more than 384 versions across npm, PyPI, and Crates.io; the PyPI packages ran node -e at import time to fetch and execute a remote JavaScript payload, meaning the malicious logic lived on attacker infrastructure and could change after publication without triggering a new PyPI release or a new hash for reviewers to flag. Snyk separately documented elementary-data, a malicious PyPI release aimed at data engineers that harvested cloud credentials — a reminder that the targeting increasingly follows whoever has the richest cloud access, not just whoever downloads the most packages. Static code review at publish time cannot catch a payload that doesn't exist yet.
What actually stops install-time credential theft?
Two controls address this directly, and neither depends on trusting the package author. First, forcing wheel-only installs with pip install --only-binary :all: skips setup.py execution entirely for any package that ships a wheel, closing off the dominant vector documented across the fabrice, LiteLLM, and TrapDoor cases. Second, running installs inside an application sandbox — restricting the filesystem and network syscalls available to install-time code — limits the blast radius even when a build script does need to run, since a sandboxed process can't read ~/.aws/credentials or reach an exfiltration endpoint it was never granted a path to. Neither control depends on recognizing a specific malicious package name in advance, which matters given how fast typosquat and compromised-maintainer campaigns rotate identities.
How Safeguard helps
Safeguard's Package Firewall runs as an install-time proxy in front of pip and npm, so every fetch — including transitive dependencies pulled in without a developer ever naming them directly — is evaluated before it reaches disk. Its behavioral analyzer introspects a package archive statically, without executing any code, to surface indicators like the auto-execution and outbound-connection patterns seen in the LiteLLM and TrapDoor campaigns, alongside dedicated typosquat and dependency-confusion detection that would have flagged a name like fabrice riding on fabric's popularity. Teams can run it in audit mode to baseline behavior before enforcing, or use quarantine mode to hold a flagged package out of resolution and route it to review, with an auto-release loop once a hold clears as a false positive or a newly-vetted release — every decision, in either mode, recorded to a tenant-scoped audit log rather than left to an individual developer's judgment about whether a pip install output looked normal.