Skip to content

Product1 publisher3 min readPublished

npm v12 turns lifecycle scripts off by default. That only helps if review policy changes too

The cheapest way to run code on a developer's machine now needs approval. Checkmarx expects attackers to move to runtime, and developers to start rubber-stamping the prompt.

The Product Desk · Product desk

Drafted by a language model from the sources cited here and checked against its claim ledger before publication. How we use AISend a correction

What happened

  • npm v12 blocks dependency lifecycle scripts by default unless they are explicitly allowed, closing off a common software supply chain attack path.
  • Before this change, installing a package from npm caused any lifecycle script bundled with it to run automatically, with no review, no approval and no second look.
  • A poisoned package with a malicious postinstall script does not require a developer to do anything other than run npm install.
  • In npm v12, lifecycle scripts no longer execute automatically during installation and developers have to approve them first.
  • Checkmarx warns attackers may respond by shifting malicious behaviour from install-time scripts to code that executes when compromised packages run, for example when a package is imported or used.

Compiled by The Product DeskSomething wrong?How this is made

Why it matters

npm v12 no longer runs dependency lifecycle scripts automatically during installation; they are blocked unless explicitly allowed, and developers have to approve them first [4][7]. That closes the cheapest known path for getting attacker code onto a developer machine, because until now any script bundled with a package ran on install with no review, no approval and no second look [5].

The economics of the old path were hard to beat. A poisoned package with a malicious postinstall script required nothing from the victim beyond running npm install [6]. Removing that removes an attacker's guarantee of execution, and attacker cost is one of the few levers defenders actually control [8].

What it does not remove is the incentive to compromise the package in the first place [8]. Checkmarx's analysis argues attackers will simply relocate the payload from install-time scripts into code that executes when the compromised package runs [11]. Darren Meyer, security research advocate at Checkmarx [9], put it as follows: "It's a bit like locking a door in a glass house: robbers will just start breaking windows" [12]. His reasoning is about effort rather than capability: lifecycle scripts get used because they are nearly guaranteed to execute, runtime infection takes more work, and with the door locked that extra work becomes worth doing [13].

The second failure mode is procedural, and it is the one operators can actually manage. A prompt is only a checkpoint if someone reads it, and Checkmarx warns the protection weakens if developers routinely allow scripts without sufficient review [14]. Meyer expects exactly that: developers under pressure to ship will get used to approving scripts they know are usually safe, a cursory look is unlikely to catch cleverly hidden malicious content, and the likely end state is approving without reading or finding a way to auto-approve everything [15]. Which means upgrading npm changes the default but not the decision, because the decision still sits with a developer mid-sprint [10].

The recommendation from Checkmarx is not "ignore scripts and call it done." Meyer frames allowlisting as a shared decision between security and engineering rather than a blanket restriction handed down [1]. In practice that means an allowScripts policy that denies lifecycle scripts which are not essential and approves those assessed as acceptably safe, backed by configuration management that makes strict-allow-scripts the default npm behaviour, which he argues reduces alert fatigue while keeping a safety net [2]. The target is not zero scripts, since some packages genuinely need theirs to function; it is fewer unreviewed ones, enforced by default rather than left to individual judgement calls [3].

The operator reading of this is straightforward. If your response to npm v12 is a version bump, you have converted a silent execution risk into an approval queue that your team will learn to clear quickly [15][10]. The durable version is a checked-in allowlist, a default enforced by configuration management rather than by the person typing the install command [2], and detection that assumes payloads now fire at import or use time rather than at install [11].

Worth watching: whether real-world malicious packages start shipping runtime payloads instead of postinstall hooks [11], and whether teams end up with auto-approve workarounds that restore the old behaviour under a new name [15].

Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories