Skip to main content

Authors: Jakub Pavlík, Marco Rodrigues

The recent security incident involving the popular lottie-player library once again highlighted the fragility of the NPM ecosystem’s security. While NPM provides robust security features like provenance attestation, many of the most downloaded packages aren’t utilising these critical security measures.

What is NPM Provenance?

NPM provenance is a security feature that creates a verifiable connection between a published package and its source code repository introduced last year. When enabled, it provides cryptographic proof that a package was built from a specific GitHub repository commit using GitHub Actions or Gitlab runners. This helps prevent supply chain attacks where malicious actors could publish compromised versions of popular packages. However, it’s important to note that this security relies on the integrity of your build environment itself — if your GitHub/GitLab account or CI/CD pipeline is compromised, the provenance attestation could still be generated for malicious code. Therefore, securing your source control and CI/CD infrastructure with strong access controls, audit logging, and regular security reviews remains critical.

The Current State of Popular NPM Packages

Let’s examine some of the most downloaded NPM packages and their provenance status:

Among the 2,000 most downloaded packages on jsDelivr, 205 packages have a public GitHub repository and directly publish to npm using GitHub Workflows. However, only 26 (12.6%) of these packages have enabled provenance — a security feature that verifies where and how a package was built. Making this incremental change to their GitHub workflows would be a significant security improvement for the entire community at large.

Critical Gaps in NPM’s Security Model

Server-Side Limitations

The NPM registry currently lacks critical server-side enforcement mechanisms:

1. No Mandatory Provenance

  • Packages can be published without any attestation
  • No way to enforce provenance requirements for specific packages or organizations
  • Registry accepts packages with or without verification

2. Missing Policy Controls

  • Organizations cannot set requirements for package publishing
  • No ability to enforce provenance for specific package names or patterns similar to git branch protection
  • No automated verification of build source authenticity

3. Version Control

  • No mechanism to prevent version updates without matching provenance
  • Cannot enforce stricter requirements for major version updates

Client-Side Verification Gaps

npm/yarn client tools also lack essential security controls:

1. Installation Process

2. Missing security Features

a) No built-in flags to require provenance
b) Cannot enforce organization-wide attestation policies
c) No way to verify single package attestation

3. package.json limitations

The Lottie-Player Incident

The recent compromise of the lottie-player library serves as a stark reminder of what can go wrong. The attack timeline:

  1. Attackers gained access to the maintainer’s NPM account
  2. Published a malicious version of the package
  3. Users automatically received the compromised version through unpinned dependency updates and direct CDN links
  4. Malicious code executed on affected systems

Had the provenance attestation been enforced at either the registry or client level, this attack could have been prevented.

Why Aren’t More Packages Using Provenance?

Several factors contribute to the low adoption of NPM provenance:

  1. Awareness Gap: Many maintainers aren’t familiar with the feature
  2. Implementation Overhead: Requires GitHub Actions workflow modifications
  3. Legacy Systems: Existing build pipelines may need significant updates
  4. False Sense of Security: Reliance on other security measures like 2FA
  5. Lack of Enforcement: No pressure to implement due to missing registry requirements

To enable provenance for your NPM packages:

Or do it in package.json in

Package Provenance check

The npm command audit can check the integrity and authenticity of packages, but it doesn’t allow you to verify individual packages — only all packages in a project at once.

NPM with invalid attestations

Since the npm CLI doesn’t provide an easy way to do this, I wrote a simple script to check the integrity and attestation of individual packages. This script makes it straightforward to validate each package.

This script can be used in a GitHub Workflow on the client side or as a monitoring tool to continuously check the attestation of upstream packages.

Client-Side Script Integrity Verification

While NPM provenance helps secure your package ecosystem, web applications loading JavaScript directly via CDN links need additional security measures. The Subresource Integrity (SRI) mechanism provides cryptographic verification for externally loaded resources. The Lottie-player attack was particularly devastating due to three common but dangerous practices:

1. Using latest tag

2. Missing integrity check

3. No Fallback Strategy

SRI works by providing a cryptographic hash of the expected file content. The browser:

  1. Downloads the resource
  2. Calculates its hash
  3. Compares it with the provided integrity value
  4. Blocks execution if there’s a mismatch

When integrity check verification fails, the browser does not allow javascript executing with the sample error

Recommendations for the Ecosystem

1. Package Maintainers

  • Enable provenance attestation immediately
  • Document provenance status in README files
  • Use GitHub Actions for automated, verified builds

2. Package Users

  • Check provenance status before adding new dependencies
  • Prefer packages with enabled provenance. Check websites such as TrustyPkg to understand its trustworthiness based on activity, provenance, and more
  • Monitor existing dependencies for provenance adoption

3. Platform Providers

  • Make provenance status more visible in NPM registry UI
  • Provide tools for bulk provenance verification
  • Consider making provenance mandatory for high-impact packages
  • Implement server-side enforcement mechanisms
  • Add client-side verification tools

4. NPM Registry

  • Add organization-level provenance requirements
  • Implement mandatory attestation for popular packages
  • Provide API endpoints for provenance verification
  • Provide package approval process / workflow

Conclusion

The security of the NPM ecosystem affects millions of applications worldwide. The current lack of enforcement mechanisms at both the registry and client levels creates a significant security risks. While provenance attestation is available, the inability to enforce it systematically leaves the ecosystem vulnerable to supply chain attacks.

The NPM team should prioritize implementing both server-side and client-side enforcement mechanisms. Until then, the community must rely on manual verification and best practices. Package maintainers should enable provenance attestation immediately, while users should demand better security controls and verification tools.

Only by working together to improve NPM’s infrastructure can we create a more secure JavaScript ecosystem. At ExaForce, we’re committed to taking the first step by helping open-source libraries adopt provenance attestation in their publishing process.

References