Secure Coding with AI - Supply Chain Protection for Node Projects and Guardrails for Agents

Published: 2/5/2026

Practical security defaults for npm and pnpm so AI-assisted coding does not turn into a supply chain risk.

Short version: If you let AI or agents write code and install dependencies, you need safety rails. This guide gives you practical defaults, sensible workflows, and a least-privilege mindset for running server-side code.


Why this matters right now

In the JavaScript ecosystem, new packages and updates ship every day. That is great for innovation, but it also opens the door to supply chain attacks.

Recent example: compromised npm versions around the Axios ecosystem (malicious versions / remote access trojan). Background and analysis:

Typical attack paths:

Goal: Even if something goes wrong, the blast radius should stay small.


1) 60 seconds: what npm actually is

Important: You are pulling in code from the outside world. That is the core supply chain risk.


2) The biggest risks during install

2.1 Malicious updates or new packages

2.2 Lifecycle scripts during install

Packages can automatically run scripts during install:

There can be valid reasons for this, such as native binaries or build steps, but it is also an attack surface.


3) The 2 most important immediate measures

3.1 Release cooldown: do not trust brand-new releases

Use a cooldown window, for example 7 to 14 days.

Important: This option currently belongs to pnpm, not the npm CLI.

pnpm-workspace.yaml:

minimumReleaseAge: 20160

20160 minutes equals 14 days.

Why this helps: If a compromised package was just published, you do not pick it up immediately.

Tip: For production systems, 7 to 14 days is often a good starting point. For very sensitive projects, consider 30 days.

3.2 Block install scripts

.npmrc:

ignore-scripts=true

What happens then? Dependencies do not run preinstall or postinstall scripts. That lowers risk, but some packages depend on those steps and may break.


4) Why postinstall can still be “necessary”

Some packages need install-time steps for:

If you enable ignore-scripts=true, this can cause errors.

A pragmatic approach:

Important: never leave scripts globally enabled forever “just so everything works” if your actual goal is security.


5) AI and agents: the most important policy

When AI or agents work in your repo, the risk is not “AI is evil”. The real issue is: AI is fast.

5.1 Golden rule

Agents must not install dependencies without approval.

5.2 Minimal policy

If the AI wants to install a package, it must provide:

  1. Why is the package needed? (specific use case)
  2. Alternatives (native solution? already available in the project?)
  3. Risk check (repo or owner, downloads, maintenance, recent releases)
  4. Minimal scope (smallest possible addition, no unnecessary tool sprawl)
  5. Test plan (how do we verify nothing is broken or malicious?)

6) Reproducible installs: lockfile plus CI

This is not flashy, but it is extremely effective.

6.1 Commit the lockfile

6.2 Strict CI installs

Why: No surprise version jumps in CI or production builds.


7) Audits: useful, but do not trust them blindly

Pragmatic approach:


8) pnpm and Yarn: short comparison

If you are already considering pnpm:

8.1 pnpm: allowlist for build scripts

pnpm v10 leans heavily into the idea that dependencies should not be allowed to run arbitrary install scripts automatically. Instead, you can explicitly allow which packages are permitted to run build scripts.

In practice, this looks like an allowlist or approval flow such as:

Takeaway for a video or course: pnpm gives you a middle ground between “scripts completely off” and “scripts always on”.


9) Runtime security: least privilege for Node, Bun, and server code

Even if a malicious package gets in, you still want to prevent it from reading or writing everything.

9.1 Core principles

9.2 Most practical option: containers

Advantage: easy to explain and very teachable.

9.3 Alternative: systemd sandboxing on Linux

9.4 Alternative for strict runtime permissions: Deno

Deno has an explicit permission system for read, network, and environment access. That makes it easy to demonstrate:

9.5 Bun

Bun is Node-compatible, but does not provide a comparable permission model like Deno. → In practice, you isolate it through containers, systemd, or the OS.


10) Copy/paste: secure project defaults

10.1 pnpm-workspace.yaml for release cooldown

# Cooldown for brand-new releases
minimumReleaseAge: 20160

10.2 .npmrc for install scripts

# Do not run lifecycle scripts from dependencies
ignore-scripts=true

10.3 Short team rule


11) Frequently asked questions

”Doesn’t ignore-scripts break a lot of things?”

Yes, some packages depend on it. That is exactly why it is a security default. If you need scripts:

”What about vibe coding?”

Vibe coding is fine, but package installation is a security boundary. That is where you need an extra rule.


12) Next steps

If you want, I can also publish: