Secure Package Management
Hardening NPM and Python dependencies against supply chain attacks. Protect your builds from malicious packages and compromised maintainers.
Most of this is free and straightforward: lockfiles, package-manager policy, and stricter install settings can materially reduce risk without buying an expensive vendor platform.
Recent Notice: Axios npm compromise
Axios maintainers confirmed that [email protected] and [email protected] were malicious npm releases published through a compromised maintainer account on March 31, 2026. Those versions pulled in plain-crypto-js and were live for roughly three hours before removal.
If your lockfile or install logs show either affected Axios version or plain-crypto-js, treat that workstation or CI runner as potentially compromised, not merely out of date.
Quick Check
grep -E '"version": "(1\.14\.1|0\.30\.4)"|plain-crypto-js' package-lock.json 2>/dev/null
grep -E 'axios@.*(1\.14\.1|0\.30\.4)|plain-crypto-js' yarn.lock pnpm-lock.yaml 2>/dev/null
The Axios post-mortem recommends a simpler grep axios@... pattern, which works well for yarn.lock and for catching plain-crypto-js broadly. This page uses lockfile-type-specific patterns because npm's package-lock.json stores resolved versions in a packages object's version field, not in [email protected] strings, so the generic pattern can miss a compromised Axios entry in npm lockfiles.
- Downgrade or repin to
[email protected]or[email protected]. - Remove
node_modules/plain-crypto-js/and reinstall from a known-good lockfile. - Rotate credentials, tokens, and secrets exposed to that machine or CI job.
- Review network and EDR telemetry for connections to
sfrclak[.]comor142.11.206.73:8000. - Prefer delaying newly published packages in CI and on developer workstations so short-lived malicious releases are less likely to land.
This repository's current package-lock.json has an empty packages object and does not show an Axios install, but the broader guidance still matters for any Node environment you operate elsewhere.
Notable Supply Chain Attacks
Real-world incidents that demonstrate why supply chain security is critical:
[email protected] and [email protected], which pulled in plain-crypto-js and dropped a cross-platform trojan. Post-mortemHardening NPM and Python Dependencies: Mitigating Supply Chain Attacks
Open-source supply chain attacks are a significant and evolving threat to modern software development. Attackers frequently target build tools and local developer environments rather than waiting to exploit application code in production. By compromising maintainer accounts, using typosquatting, or exploiting dependency confusion, malicious code is injected directly into public registries.
In both NPM and PyPI, the risky path is any install flow that executes dependency-controlled code: Node lifecycle scripts such as preinstall and postinstall, and Python source builds that invoke PEP 517 backends or legacy setup.py. This includes npm lifecycle hooks such as preinstall, install, and postinstall. Dependency install and build scripts execute arbitrary code with developer or CI privileges. These scripts typically have access to developer secrets, CI tokens, and internal package infrastructure.
Effective hardening combines strict lockfiles, delayed adoption of newly published releases, explicit approval of dependency install and build scripts, and extra isolation for higher-risk installs. Controls must be enforced in CI and shared config, not only local developer environments. These attacks typically result in credential theft, CI compromise, or unauthorized package publishing.
1. JavaScript/TypeScript: Using pnpm
pnpm v10 is a strong default for Node projects because dependency lifecycle scripts are blocked unless you explicitly approve them. It also includes built-in controls for release-age delays, trusted build approvals, and blocking exotic transitive dependency sources. See the pnpm supply chain security guide and the settings reference.
Action: Commit a pnpm Policy to the Repository
Keep the security policy in pnpm-workspace.yaml so developers and CI runners enforce the same rules.
Enable pnpm and Migrate Project
# Enable pnpm via Corepack (Node.js 16.17+)
corepack enable pnpm
# Migrate an existing project
rm -rf node_modules package-lock.json
pnpm import # Generates pnpm-lock.yaml
Project Security Policy (pnpm-workspace.yaml)
# Delay adoption of brand-new releases
minimumReleaseAge: 1440
# Block git/tarball transitive dependencies
blockExoticSubdeps: true
# Fail installs when unreviewed dependency install and build scripts appear
strictDepBuilds: true
# Approve only the dependency builds you trust
allowBuilds:
esbuild: true
# Optional when your workflow supports pnpm trust signals
# trustPolicy: no-downgrade
pnpm approve-builds to review pending scripts, then commit the resulting allowBuilds policy. Avoid relying on global ignore-scripts=true as the main pnpm workflow in v10; it is broader than necessary and also disables your project's own scripts.
2. Python: Using uv
Standard pip workflows can execute arbitrary code when an installation falls back to a source distribution. That execution path now commonly runs through PEP 517 build backends, not just legacy setup.py files.
uv is a fast Python package manager and resolver. Its native workflow uses pyproject.toml to declare dependencies, uv.lock to lock them, and uv sync to reproduce that environment. The pip-compatible subcommands are still useful for existing requirements.txt-based repositories or for export paths, but they are not the primary uv model. A high-trust workflow should still refuse source builds unless you explicitly allow them. See the uv projects guide, the locking and syncing guide, and the uv CLI reference.
Action: Prefer Native Locks, Export When Needed
For the default workflow, commit pyproject.toml and uv.lock, then use uv sync to reproduce that environment. If another tool still requires requirements.txt, export from the lockfile rather than treating hand-maintained requirements files as the source of truth. For stricter installs, combine that with --no-build so the sync fails rather than building from an sdist.
Install uv
# Install uv (Mac/Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh
Workflow for Secure Python Management
Native uv Project Workflow
# Create an isolated virtual environment
uv venv
source .venv/bin/activate
# Add direct dependencies to pyproject.toml
uv add requests==2.31.0
# Resolve and write uv.lock
uv lock
# Reproduce exactly what is locked
# --locked refuses to update the lockfile
# --no-build fails if a wheel is unavailable and a source build would be required
uv sync --locked --no-build
If you need a requirements.txt for a scanner, legacy deploy target, or another downstream tool, export it from the locked state instead of maintaining a separate primary workflow. If a dependency is only available as an sdist, treat it as an exception and isolate that install path deliberately.
3. Scaling to Enterprise Environments (CI/CD)
Securing local developer machines is only part of the process; build pipelines require the same level of strictness.
Proxy Registries
Avoid pulling directly from public registries like npmjs.org or pypi.org in CI pipelines.
- Route traffic through a private artifact proxy (e.g., JFrog Artifactory, Sonatype Nexus).
- Enable quarantine policies on the proxy to automatically block packages with low reputation scores or newly published versions, effectively enforcing a network-wide release delay.
Enforce Configurations in CI Pipelines
GitHub Action: Enforcing uv Lockfile Sync
steps:
- uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v2
- name: Install dependencies strictly
run: uv sync --locked --no-build
GitHub Action: Enforcing pnpm Policy
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v3
with:
version: 10
- name: Install with committed policy
run: pnpm install --frozen-lockfile
Summary
Supply chain attacks exploit default configurations and implicit trust in package registries. Moving to pnpm with a committed build policy, using uv with committed native locks and strict sync behavior, and delaying newly published package versions will significantly reduce exposure while preserving practical developer workflows.