Skip to content

Package Registries

Enforce a Minimum Package Age — Critical

Most malicious package versions are removed within hours, or a few days, of publication. A minimum-age policy can significantly reduce the impact of upstream compromises. pip, npm, uv, Dependabot, and Renovate all support this functionality. Target 7 days as a reasonable starting point.

Tip

Regardless of which registry is being used, make sure to apply the same package age policy to automation tools such as Dependabot and Renovate, otherwise they will continue opening PRs the package manager refuses to install.

npm (CLI 11.x+):

minimumReleaseAge config, value in minutes.

npm config set minimumReleaseAge 10080 --location=global

Ref: npm Docs — Config

pnpm (10.16+):

Set in pnpm-workspace.yaml. Defaults to 1440 in v11.

pnpm-workspace.yaml
minimumReleaseAge: 10080

Ref: pnpm Docs — Mitigating supply chain attacks

uv:

--exclude-newer accepts RFC 3339 timestamps or relative durations (7d, 1w, P7D).

# friendly duration
uv sync --exclude-newer "7 days"

# ISO 8601
uv sync --exclude-newer P7D
Persist the setting per-project in pyproject.toml.

pyproject.toml
[tool.uv]
exclude-newer = "7 days"

Ref: uv Docs — Resolution

pip (26.0+):

--uploaded-prior-to is per-invocation only. Set it in CI and via pip.conf. There is no persistent project-level equivalent yet.

pip install --uploaded-prior-to "7 days" -r requirements.txt

Ref: pip Docs — pip install

bun (1.3+):

# Only install package versions published at least 7 days ago
bun add @types/bun --minimum-release-age 604800 # seconds

minimumReleaseAge can also be set in bunfig.toml.

bunfig.toml
[install]
# Only install package versions published at least 7 days ago
minimumReleaseAge = 604800

Ref: bun Docs

yarn (4.10.0+):

npmMinimalAgeGate set in relative durations in .yarnrc.yml.

.yarnrc.yml
npmMinimalAgeGate: "7d",

Ref: yarn Docs

Pin Dependencies by Hash — Critical

Version strings (e.g.: @v1 or @latest) alone don't verify content. Hash pinning avoids substitution attacks and ensures the integrity of dependencies.

Python:

pip install --require-hashes -r requirements.txt
# generate with: pip-compile --generate-hashes
# or: conda-lock for conda environments

npm:

# package-lock.json records content hashes automatically
# use npm ci in CI — never npm install (which allows lockfile mutation)

Hash pinning does add some management overhead. Use Dependabot or Renovate to automate this process.

Audit Installed Environments Regularly — High

pip-audit                            # checks installed packages against OSV/PyPI advisory DB
pip-audit -r requirements.txt --fix  # auto-remediate where possible
npm audit                            # npm equivalent

Run pip-audit in CI on every dependency change. For environments with AWS tooling (boto3, botocore, awscli), treat any advisory as significant. These are primary credential-exfiltration targets in active campaigns (TeamPCP, March–May 2026).

Avoid Execution of Lifecycle Scripts — Medium

The TanStack malware and the PyTorch Lightning compromises both executed during npm install / pip install via lifecycle hooks (prepare, postinstall) and optionalDependencies. These run automatically with no additional prompt.

For npm, consider --ignore-scripts in CI for packages that don't require build steps, or use a lockfile auditor that flags new lifecycle scripts introduced between versions. Configure .npmrc with ignore-scripts=true as a project default.

Important

Traditionally, vulnerabilities in the build environment were ignored as they were not accessible or exploitable in the production deployment. This is no longer the case. The build environment itself is being exploited with significant impact.

Mirror Approved Packages Internally — Medium

An internal mirror with an explicit allowlist prevents typosquatting, dependency confusion attacks, and pulls from attacker-controlled PyPI mirrors.

Options: Artifactory, Nexus, devpi (Python), Verdaccio (npm). Configure pip via pip.conf index-url pointing to the internal mirror only; block direct egress to pypi.org/npmjs.com from CI runners.