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-agesetting 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 withnpm --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:
- You always specify exact versions in your
pom.xml. - There are no
preinstall/postinstallscripts, which makes attacks a bit less straightforward. - Packages uploaded to Maven Central need to be signed with the corresponding private key, which is harder to obtain than an npm publish token.
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!