npm install explicit-trust controls
Summary
JFrog Security Research documented npm v12's move from implicit install-time trust to explicit approvals for the three npm dependency-ingestion paths most often abused by recent supply-chain malware: lifecycle scripts, Git dependencies, and remote URL dependencies. On July 8, 2026, GitHub announced that npm v12 is generally available and tagged latest, turning those install-time security defaults on in the shipped release rather than leaving them as an upcoming change.
StepSecurity's June 2026 developer-machine package-configuration guidance adds the fleet-control side of the same pattern: registry, cooldown, and authentication policy only protects hosts that are actually configured to use it. Treat package-manager configuration drift on laptops and CI runners as an exposure class, not a compliance footnote.
Elastic Security Labs' August 2026 implementation report adds a concrete way to detect that drift. Elastic monitors .npmrc as current configuration state, not as an append-only log, so removal of min-release-age becomes an explicit signal instead of leaving a stale “configured” event in the index. The design also filters registry-token lines on the endpoint before telemetry leaves the workstation.
Track this as a defender pattern rather than a single operation. The same install-time execution paths have appeared across Shai-Hulud / Miasma, Mastra easy-day-js, binding.gyp, and other developer-machine compromise chains. npm v12 reduces one default execution path, but it does not remove the need to govern approved scripts, Git dependencies, remote URL dependencies, package-manager configuration drift, import-time execution, and runtime package behavior.
Tags
- patterns
- supply-chain
- npm
- npm v12
- JavaScript
- lifecycle-hooks
- install-time-execution
- developer-workstations
- CI-CD
- package-manager-hardening
- registry-controls
- package-cooldowns
- developer-machine-fleet
- bypass2fa
- granular access tokens
- Shai-Hulud
- Miasma
What changed
- GitHub's July 8 changelog says npm v12 is now generally available and tagged
latest; teams should stop treating the new install-time defaults as future planning and start testing real project behavior. allowScriptscontrols which third-party packages may run lifecycle scripts during install, includingpreinstall,install,postinstall,prepare, and implicitbinding.gypnative-build execution.- npm v12 changes the default posture so third-party lifecycle scripts do not run unless explicitly approved.
--allow-gitgates direct and transitive Git repository dependencies.--allow-remotegates direct and transitive remote URL dependencies.- JFrog said these three vectors appeared in about 53% of malicious npm attacks it observed over the prior year, with lifecycle scripts alone appearing in about 46% of observed malicious npm packages.
- GitHub also began deprecating granular access tokens with
bypass2faprivileges. As of July 31, those tokens can no longer create or delete tokens; change package access, maintainers, or trusted-publishing configuration; or manage organization/team membership and package grants. Those operations now require an interactive 2FA challenge. This restriction applies to npm granular access tokens, not GitHub PATs, GitHub App tokens, or ActionsGITHUB_TOKEN. - Direct publication with npm 2FA-bypass tokens remains temporarily available, but GitHub targets January 2027 for removing it. The remaining surface is expected to permit reading private packages and staging a publish that a maintainer approves with 2FA. Migrate automation to trusted publishing with OIDC or staged publishing rather than treating the current management-action restriction as full token retirement.
- npm
11.10and later supportmin-release-age=<days>, which excludes versions newer than the configured age from dependency resolution. Elastic uses a seven-day value and re-applies it daily in its macOS fleet; the value and enforcement mechanism are organization choices, not universal defaults. - Capability inventory can overstate protection. Node Version Manager can leave several npm versions on one host; they share the user
.npmrc, but npm versions older than11.10ignoremin-release-age.
Why this matters
- Recent npm worms and credential stealers have relied on automatic install-time execution because it runs on developer machines and CI runners before application code is reviewed.
- Blocking scripts by default reduces the blast radius of newly published malicious versions and typosquats, especially when combined with registry cooldowns and internal mirrors.
- Git and remote URL dependencies bypass some registry-centric controls; requiring explicit allowance makes those dependency sources visible policy decisions.
- Native-module builds deserve special review: packages that legitimately need
node-gypor postinstall downloads can become high-value compromise targets because organizations may pre-approve their scripts. - Internal registries, secure registries, and package-version cooldowns are only effective when developer machines and CI runners consistently use them. A single laptop with a direct public-registry path can become the first compromised host in a supply-chain incident.
- Cooldown state is not append-only telemetry. npm can rewrite
.npmrcin place or delete the file when its final setting is removed; a file-tail input may retain the last positive event without emitting the removal that defenders need to see.
Attacker adaptations to expect
- Compromise of packages that are already approved in an organization's
allowScripts/approve-scriptsconfiguration. - Migration from install-time execution to import-time execution, where code runs when a package is imported by application or build tooling.
- Runtime invocation payloads hidden behind normal-looking API calls or build steps. Confirmed in the wild Sep 22, 2026: Checkmarx's
indexed-btreeteardown (via The Hacker News) documents a campaign that abandons lifecycle scripts entirely after npm 12, the loader hides insideBTree.prototype.set(), fires at runtime, and then deletes its own artifacts and strips its own trigger from the package code. Recorded in full on the Equation of Compromise page (the same btree-name family sits in JFrog's download-farm target list; stated realized profit €230,933 / 109 ETH). - More abuse of trusted package maintainers, release automation, and transitive dependencies that inherit approval decisions.
- Social engineering or documentation changes that ask developers to run installs with broad
--allow-*flags.
Defender heuristics
Policy and inventory
- Inventory
.npmrc,package.json, lockfiles, package-manager wrappers, and CI templates for current script, Git dependency, and remote URL behavior. - Inventory Python package-manager configuration alongside npm:
pip.conf,pip.ini,pyproject.toml,requirements*.txt,PIP_INDEX_URL,PIP_EXTRA_INDEX_URL, and tool-specific config for Poetry, uv, and pip-tools. - Verify whether each developer machine and CI runner resolves packages through the intended internal registry / secure registry, whether fallback to public indexes is allowed, and whether package-version cooldown policy is actually enforced at the endpoint.
- Audit package-manager authentication posture: remove stale registry tokens, eliminate granular access tokens that retain legacy
bypass2fapublication privileges, avoid shared long-lived tokens on developer machines, and prefer scoped credentials that cannot publish or read unrelated private packages. - Review automation for account, organization, team, maintainer, package-access, and trusted-publishing changes formerly performed with npm bypass-2FA tokens; move those actions to an interactive, phishing-resistant 2FA path and alert on failed legacy attempts.
- Treat every existing lifecycle-script approval as a privileged allowlist entry; record who owns it, why it is needed, and how updates are reviewed.
- Prefer package-specific approvals over broad flags that allow all scripts or all non-registry dependency sources.
- Require review for dependency changes that introduce Git URLs, tarball URLs,
preinstall,postinstall,prepare, orbinding.gyppaths.
CI / developer hardening
- Roll npm upgrades deliberately: test npm v12 behavior on representative projects before forcing fleet-wide adoption, then remove compatibility bypasses once packages are remediated.
- Pair npm v12 controls with registry cooldowns, internal mirrors, and malicious-package blocking; npm's install controls do not replace package intelligence.
- Continuously check package-manager configuration drift on developer laptops, not only in golden images. Attackers only need one host that bypasses the internal registry or cooldown path.
- Fail closed when a workstation or runner cannot reach the approved registry path; do not silently fall back to the public npm or PyPI indexes during outages.
- For CI, fail closed when a dependency needs a newly unapproved script or non-registry source instead of falling back to permissive install flags.
- Monitor build logs for
--allow-git,--allow-remote, broad script approvals,--ignore-scriptsbypass workarounds followed by manual execution, and unexpectednpm rebuildbehavior.
Detection pivots
- Alert on lifecycle scripts added to packages that did not previously need install-time execution.
- Alert when package-manager config changes introduce public-index fallback, disable cooldown enforcement, add broad extra indexes, or replace an organization registry with direct upstream npm / PyPI access.
- Monitor user and machine-global npm configuration as snapshots or another state-aware data source. Elastic's reference design checks user
.npmrcfiles plus platform-global paths on a six-hour heartbeat and marks a present file without the key ascooldown.absent = true. - Distinguish a missing cooldown key, a deleted configuration file, an offline endpoint, and an npm binary too old to enforce the key. A time-windowed dashboard needs periodic current-state reports or equivalent host-liveness context; one-shot change events age out and can create false adoption decline.
- If configuration files can contain registry credentials, allowlist the required keys before collection leaves the endpoint. Filtering
_authTokenor other secret-bearing lines only in a central ingest pipeline is too late. - Do not infer state-file removals from append-oriented log tailing alone. Elastic found that small
.npmrcfiles also fall below Filebeat filestream's default 1,024-byte fingerprint threshold unless native file identity is selected; snapshot semantics address the more fundamental removal-detection gap. - Correlate package approval changes with maintainer-account changes, newly published versions, and package-source repository changes.
- Hunt for developer or runner processes where
npmspawns shells, network tools, Python, Bun, native compilers, or updater-like binaries during dependency installation. - Continue import-time and runtime scanning; npm v12 controls reduce install-time execution but do not stop malicious code that waits for application import or invocation.
Related pages
- npm publish-time malware scanning and dual-use declarations
- Dependabot cross-ecosystem malware advisory alerts
- binding.gyp npm CI/CD worm
- Mastra
easy-day-jsnpm scope compromise - Mini Shai-Hulud npm/PyPI worm campaign
- Developer-tool config auto-execution
Sources
- JFrog Security Research: https://jfrog.com/blog/npm-v12-from-implicit-to-explicit-trust/
- StepSecurity: https://www.stepsecurity.io/blog/prevent-npm-and-python-supply-chain-attacks-on-developer-machines-with-package-configs
- GitHub Changelog: https://github.blog/changelog/2026-07-08-npm-install-time-security-and-gat-bypass2fa-deprecation/
- GitHub Changelog, “Restricting npm bypass-2FA granular access tokens,” 2026-07-31: https://github.blog/changelog/2026-07-31-restricting-npm-bypass-2fa-granular-access-tokens
- Socket: https://socket.dev/blog/npm-12
- Elastic Security Labs, “The security signal log tailing can't see: tracking npm cooldown removals with Elastic Agent,” 2026-08-07: https://www.elastic.co/security-labs/npm-cooldown-removal-detection-elastic-agent