CodeSOD: Patching Over Your Problem

Deanna inherited some code which had gone through many, many previous hands. Like a lot of JavaScript/TypeScript code, it needed to be able to compare objects for deep equality. This is fraught and complicated, and there are many many many solutions available in NPM.

NPM, of course, is its own fraught thing. Widely used libraries frequently have vulnerabilities, and even if you don't use them directly, the nature of dependency management via NPM means that libraries your libraries depend on might.

If you want to avoid that, you could whip up your own deep equals function, with a little recursion. Or, if you're a real hack, you might gamble on JSON.stringify(a) == JSON.stringify(b) working (which is a gamble, as it depends on key insertion order being the same).

Deanna's predecessors found a different solution. They did go off to use a library- but the library they chose is a bit surprising for this task.

import * as JsonDiff from 'rfc6902'; /** * Checks if objects are equal */ function isDeepEqual(o1: Object, o2: Object): boolean { return JsonDiff.createPatch(o1, o2).length === 0; }

This calls the library rfc6902, which implements that RFC. RFC6902 includes conventions for describing JSON documents and methods of mutating them, like patch documents. This entire library is included for just this method, and specifically that createPatch call. That walks through the objects, recursively, to build a patch document, which contains instructions to add, delete, modify or move fields in order to make the object identical. As you can imagine, that task is much more complex and expensive than just comparing for equality, and unlike equality, where you can stop the process on the first failure, this has to look at every field in the input document.

Finally, if the patch document is empty, then the two objects match.

This is overkill. This is swatting a fly with a wrecking ball. If they had more use for the library, this might make sense, but this is the one call they make. And of course, because they've added a new dependency, they've also added its security vulnerabilities.

In this case, that's "Prototype Pollution", which isn't the most severe flaw you could have, but it does mean that a maliciously crafted object could inject its own code into the object prototype, replacing built in methods with its own methods. It's hard to exploit, but it's still a vulnerability- a vulnerability that's existed in every version of the library. A library which hasn't seen updates in 7 months, and there's a pull request even older which fixes it.

It's good to use libraries and third party code to help you solve problems. But it can't be done blindly or carelessly.

[Advertisement] Utilize BuildMaster to release your software with confidence, at the pace your business demands. Download today!

This post originally appeared on The Daily WTF.

Leave a Reply

Your email address will not be published.