Seal Security Blog

Rebuilding the Past: How Seal Security Uses an NPM Time Machine to Patch Node.js Libraries

Open source libraries often depend on specific versions of other libraries, and those dependencies might have changed over time. When a library was built years ago, the environment it depended on no longer exists in its original form. Package managers like npm are designed to handle these kinds of issues by allowing version ranges for dependencies. So, how do we ensure we have the exact versions of every dependency when trying to fix old libraries?

Rebuilding the Past: How Seal Security Uses an NPM Time Machine to Patch Node.js Libraries

At Seal Security, our mission goes beyond simply fixing vulnerabilities in open source libraries—we aim to ensure that every patch we implement keeps your applications running smoothly. Patching an old library isn’t just about addressing the vulnerability; it's also about ensuring the fixed version works exactly as it did when it was first built.

The Challenge: Evolving Dependencies

Open source libraries often depend on specific versions of other libraries, and those dependencies might have changed over time. When a library was built years ago, the environment it depended on no longer exists in its original form. Package managers like npm are designed to handle these issues by allowing version ranges for dependencies. For example, a package.json might include got@^6.6.0, which would match any version from 6.6.0 upwards, like 6.6.1 or 6.7.1.

However, version flexibility has its drawbacks. Dependencies have their own dependencies, and those may introduce subtle changes or even breaking changes with older code. Even something as small as a bug fix might inadvertently cause a compatibility issue. Consider this: fixing a bug by introducing simple input validation in an arrow function might seem harmless, but arrow functions were introduced in Node 4.0. If the library previously supported older versions, this change could actually break existing code.

Seal Security’s NPM Time Machine

So, how do we ensure we have the exact versions of every dependency when trying to fix old libraries? This is where Seal Security's NPM Time Machine comes into play. Imagine being able to rewind time and recreate the exact environment from when a particular library was first built.

Here's how it works:

  1. Extracting Release Data: We first grab the release information for the target library version (e.g., ansi-regex version 5.0.0) from the official npm registry.
  2. Building a Time Capsule: We create a server that mimics the npm registry but with a twist. Whenever a request comes in for a library, we fetch the data from the real registry but discard any versions released after the target version's build date.
  3. Time Traveling with npmrc: We configure npm to use our Time Machine server as the primary registry using a file called .npmrc.

By tricking npm into using our custom registry, we can install the exact versions of dependencies previously used by the library.

A Successful Journey Through Time

Let’s look at an example use case.

ansi-regex 5.0.0 was released back in October 2019—not that old compared to many frameworks we encounter. However, if we try to install ansi-regex 5.0.0 using the regular npm registry and then run its tests, we just get errors:

shell

Copy code

npm test

> ansi-regex@5.0.0 test
> xo && ava && tsd
...

 ✖   163 errors

Even though ansi-regex 5.0.0 only depends on three libraries (xo, ava, and tsd), something still broke. Yet, using our Time Machine set back to October 2019, the tests run flawlessly:

shell

Copy code

npm test

> ansi-regex@5.0.0 test
> xo && ava && tsd

 ✓  391 tests passed

A Game-Changer for Node.js Security

Using the Time Machine approach has been a game-changer, saving our team countless hours debugging compatibility issues. We've integrated it into our automated backporting pipeline, significantly boosting the success rate of our automated patching process.

By recreating the past development environment, we can ensure our patches don't break existing functionality, helping us keep your Node.js applications secure.

For more information, contact us at info@seal.security.

Related articles: