How to secure your JavaScript codes from risks

How to secure your JavaScript code from Risks

Given the recent npm supply chain attack that compromised chalk, I thought it would be a good idea to take a look into how to secure your JavaScript code from vulnerable dependencies. After some relatively light research, I found a few actionable tips that could be of use to many developers.

I am by no means a security expert. This is just a summary of what I found after a little bit of research. If you are a security expert and find any mistakes, please let me know!

Audit dependencies regularly

Regularly scan your project for known vulnerabilities using automated tools. The npm CLI provides a built-in auditing command:

npm audit

This will report any security issues in your dependencies. For continuous monitoring, consider integrating tools like Snyk or Dependabot into your workflow. These can automatically check for and alert you to new vulnerabilities.

:light_bulb: Tip

Double check any Dependabot PRs before merging them, review the changelog and check for breaking changes, too. Sometimes, a security patch can introduce breaking changes or do more harm than good, if something flies under the radar.

Pin dependency versions

Avoid surprises from upstream updates by locking your dependencies to known good versions. Use a package-lock.json file in combination with the npm ci command to ensure reproducible builds:

npm ci

It installs exactly what’s specified in your lockfile, preventing unintentional upgrades. Be cautious with version specifiers like ^ or ~ which can allow automatic updates:

{  "dependencies": {    "express": "4.18.2" // Prefer this    // Instead of    "express": "^4.18.2"  }}

Use trusted sources

Only install packages from reputable maintainers and sources. Before adding a new dependency, check its download count, review its code, and verify the maintainer’s reputation. Avoid packages with suspicious activity, few contributors, or poor documentation.

For example, you can inspect a package with:

npm info <package-name>

:red_exclamation_mark: Caution

In this case, the supply chain attack did indeed come from a reputable dependency (chalk), so use this advice as part of a broader strategy, not as a sole safeguard.

Minimize dependencies

Keep your dependency footprint as small as possible. Every additional package increases your attack surface. Remove unused dependencies and prefer built-in language features or your own code for simple tasks.

To identify and remove unused dependencies:

npm prune

Or use tools like depcheck to find unused packages. Additionally, if you only need a small part of a large library, consider importing just that part instead of the whole package, looking for a modular alternative, or writing a small utility function yourself.

Review transitive dependencies

Your direct dependencies may pull in many others. Regularly inspect your full dependency tree to spot risky packages. Use:

npm ls

This outputs your project’s dependency graph. Look for deprecated, outdated, or suspicious packages deep in the tree and consider alternatives if necessary.

Monitor for malicious updates

Stay informed about new vulnerabilities and malicious package updates by subscribing to security advisories and update your dependencies promptly when patches are released. GitHub provides automated alerts for repositories and npm has its own advisories:

Set up notifications in your workflow to be alerted when action is needed.