What to do as a developer against supply chain attacks (when working with Java and JavaScript)

With the rise of LLMs and AI, attacks on all kinds of vectors targeting software projects are increasing day by day. Attackers can now automate on a scale that was not possible before, be it searching code for vulnerabilities or running large-scale supply chain attacks. The latter has become a real threat to developers and their development environments lately. If you have followed the news over the past few months, you will have seen the chalk/debug compromise in September 2025, the self-propagating Shai-Hulud worm a week later, and most recently the "Mini Shai-Hulud" wave that hit hundreds of npm packages in April and May 2026.

While there are many actions you can take to improve safety and security, I want to dedicate a short guide to what I would recommend doing today as a full-stack Java/JavaScript developer to make your development workflow a bit safer.

Node and npm

The .npmrc file in your home directory

Note: the min-release-age setting requires npm CLI v11 or newer (which ships with Node.js 24). On older npm versions this line is silently ignored. You can check your version with npm --version.

# Wait at least 3 days before installing any package version.
# Most supply chain attacks are caught within hours, so this buys safety.
# Value is in seconds: 3 days = 259200
min-release-age=259200

# Don't run lifecycle scripts (preinstall, postinstall, etc.) by default.
# Blocks a common supply chain attack vector.
# You can override per-install with: npm install --ignore-scripts=false
ignore-scripts=true

# Save exact versions in package.json (e.g. "2.1.10" not "^2.1.10")
# when you run `npm install <pkg>`. Pairs well with the lock file
# for reproducible installs.
save-exact=true

The .npmrc file per project

To enforce the same settings for your team, you can also add an .npmrc to the project and commit it. In particular, you can explicitly allow scripts per project via the ignore-scripts flag. While it's more secure to keep it enabled, most projects (such as Angular-based ones) unfortunately rely on the scripts functionality.

# Wait at least 3 days before installing any package version.
# Most supply chain attacks are caught within hours, so this buys safety.
# Value is in seconds: 3 days = 259200
min-release-age=259200

# Don't run lifecycle scripts (preinstall, postinstall, etc.) by default.
# Blocks a common supply chain attack vector.
# You can override per-install with: npm install --ignore-scripts=false
# Or disable it explicitly per project.
ignore-scripts=true

# Pin the registry explicitly so a misconfigured global setting
# can't silently redirect installs to somewhere else.
registry=https://registry.npmjs.org/

# Save exact versions in package.json (e.g. "2.1.10" not "^2.1.10")
# when you run `npm install <pkg>`. Pairs well with the lock file
# for reproducible installs.
save-exact=true

Use npm ci instead of npm install in CI

In your CI pipeline, prefer npm ci over npm install. It installs exactly what is in your package-lock.json and fails the build if package.json and the lock file are out of sync. This way a compromised dependency cannot quietly slip in through a fresh resolution, and your CI builds stay reproducible.

Test if the settings are effective

Check whether the configuration you made is being picked up:

npm config get min-release-age
npm config get ignore-scripts

You can also verify the full effective configuration:

npm config ls -l

What about Java (Maven) projects?

Maven approaches some things differently. Some settings that are optional for npm are the default for Maven:

That said, you might still want a setting like min-release-age, but this does not exist for Maven at the time of writing. If you want to dig deeper, it is worth knowing that you can restrict which repositories Maven pulls from in your ~/.m2/settings.xml, enable strict checksum verification, and run a scanner like OWASP Dependency-Check in CI. And if you use Renovate or Dependabot to keep your dependencies up to date, both support a minimum release age that gives you a similar cooldown at the PR layer.

So for a "normal" project, I don't think there are straightforward recommendations or steps to take like I would recommend for Node/npm projects.

Conclusion

Supply chain attacks are not going away, and the recent worms have shown that even widely trusted packages can turn malicious within hours. The good news is that a few small changes go a long way: a release-age cooldown, disabled lifecycle scripts, pinned versions, npm ci in CI, and dependency scanning on the Java side. None of this makes you invulnerable, but it raises the bar enough that you are no longer the easiest target.

How do you protect yourself from supply chain attacks? Let me know in the comments!

javascriptjavanodejsnpmmavensecuritysupply-chainbest-practices