I think this is another example of "worse is better" [1] -- it's something that's yucky, and has a lot of flaws, but worked (for some value of worked) well enough for a lot of people.
This is one reason why a company like NPM (or whoever is behind it), or really any company that hosts dependencies, should audit and verify packages and package updates.
I'm sure there's businesses that would pay for a dependency provider that ensures all versions of all packages hosted there are reviewed, security checked and signed off on. With a warranty clause, so that if something like this does come out, they get compensated for damages (if actively exploited). A bug bounty should of course also be offered.
A bit like Apple's app store but for libraries. Or the ideal thereof anyway. Basically a library developer can't just keep spamming updates, they would have to be more careful with what they submit.
And of course, library devs would get a slice of the pie, an X amount per installation.
It probably wouldn't work because people (even large enterprises who cannot afford any security issue like this) prefer free.
This is a bug in library, something the develops did not know off. When someone has to audit every package first there will be almost no open source anymore.
The real problem is that the standard library of node/javascript is too small so you need dozens of packages for basic operations.
No one (that I'm aware of) has managed to make a successful business of "curated" packages (interested to hear if there are any).
You get companies doing things like version checking and basic scans for malware, but that wouldn't catch issues like this.
My guess is that the volume of security review you'd need to do, for it to be usable by enough companies, is massive and a lot of the review would need to be manual.
Then as you add libraries you need to dedicate resources to reviewing every new release.
As far as I'm aware, distros are not doing security review of all the packages they include. I'd be pretty surprised to find out that they have the kind of resources needed to do code review of even a small percentage of their packages.
In this case, a one-time review might have sufficed; this bugfix was the first release in five years. But generally speaking, you're 100% right — and obviously, this little package is orders of magnitude less complex than e.g. React or Express.
Tldr: Leading zeros in ips are not calculated correctly. The stated „server-side request forgery, remote file inclusion, local file inclusion, and more“ issues are not within the package, these are anticipated issues when ips pass the validation which should fail...
Isn't this good? It'll be fixed in one place, and 270k other projects will get the fix, more or less automatically? Bugs happen, I'd rather they happen this way than the code had been copied into the other projects.
I think the problem is that people (myself included) rarely update npm packages, and perhaps the upstream creators of some libraries won’t update either, mainly out of fear the update will break some part of your project.
Sure, but there is a chance you will update them, whereas if you'd homebrewed the code or copied the code in, the bug would probably never be detected or fixed. And for those who do care about their packages and deps, they update in a timely manner.
There are other alternatives. As mentioned elsewhere in the comments, there are other environments, like Ruby and Python, that don't seem to have these issues with the same severity.
NPM scared me right from the beginning. There was so much stuff getting pulled in, that it was pretty clear that this can't be secure. This is what mostly kept me away from node.
I have the same feeling about PyPI, but to a way lesser extent. Python can already do much by itself, so that the amount of packages one installs is controllable.
You have a point there, but if you have a very well vetted third-party library that provides things as basic as IP address parsing, you'll probably see that library included into the official library package.
Lodash might, or might not, offer the same guarantees that a stdlib generally offers: backwards and forwards compatibility, a clear deprecation and removal schedule, etc.
It's great to have high quality third party libraries but stuff like most of lodash should be in a stdlib, already.
Well yes, but the point is that everything in the stdlib receives scrutiny and a long-term commitment to mainenance/upkeep. A small proportion of pypi/npm receives these things, but the vast majority is abandonware trash. You only have to briefly scroll through the main PyPI index to realise just how awful it is:
Even though the documentation claims that "Leading zeroes are tolerated only for values less than 8 (as there is no ambiguity between the decimal and octal interpretations of such strings)."
In addition to the very likely improved vetting, other libraries dependent on it will be coding against an API which is less likely to receive breaking changes, unless it is a major Python release. Even then, breaking changes will be clearly announced. You won't see any pinning against a specific and possibly outdated version.
My hope is that with a larger standard library there is more shared ownership of the library at large.
With many small libraries there often is a single person working on it and others assuming "oh, somebody will have reviewed it"
This can happen with a big library as well (as individual maintainers "own" specific parts) but there it is easier to establish a review culture.
(Whether a review would have caught this specific case is yet another question, but again having an organisation could guarantee a timely response, is read if depending on a single contributor)
Trust. I can trust code that is part of Java, .Net or Python standard library is good or decent quality. With npm you can't trust anything, package can go away, malware could be inserted in them, backward compatibility could brake.
Say you grab a 10 years old Java/.Net project source and a node one, and try to setup a developer environment to be able to create a fix. Would you bet that on average is 10X harder to get stuff to run on node ?
> I can trust code that is part of Java, .Net or Python standard library is good or decent quality.
I think you’re being a little optimistic there.
Consider Java’s URL class, for instance. Its equals() implementation will resolve the hostname in both URLs and consider them equal if they resolve to the same IP address. So that’s a) completely wrong, b) a potential source of security problems (consider an attacker pointing their hostname to your IP address to control URLs that are “equal” to your URLs, for instance), c) horribly unpredictable (two URLs may or may not be the same depending on whether you are online or not), and d) awful for performance (introduces a network lookup even for hashcode(), for instance).
That’s significantly worse than a bug like this, which is essentially an oversight that failed to consider an obscure notation nobody uses.
> Say you grab a 10 years old Java/.Net project source and a node one, and try to setup a developer environment to be able to create a fix. Would you bet that on average is 10X harder to get stuff to run on node ?
Java is probably okay, but I’ve tried this with .NET and it was extremely painful.
Funny enough you mention url, I had to fix a bug recently in JS code where our project was rejecting valid urls, the issue was that someone found somewhere a regex that validated urls but during the years the standards updated and now more characters were allowed. So copy pasting perfectly good code is bad because it might get outdated.
I would bet that on average Java standard library code(that is not deprecated) will be higher quality then npm packages.
A large number of packages may be using it but the actual danger posed is very much dependent on the application using the library. That's a little hard to assess.
This is nodes contribution to the world - now every npm package bug is hyped as a security issue instead of, well, this IP input field doesn't handle octal IPs correctly.
Bonus points for security scanners that diagnose grave vulnerabilities in frontend bundles but the backend is some Python/Ruby/guaranteed-no-npm API.
Can anyone explain a scenario where this is exploitable? I don't understand how this is likely to result in SSRF, file inclusion, etc. What applications are taking user supplied IP addresses?
So one example would be. Say you have a web application which makes HTTP requests on your customer's behalf (something like a website availability checker)
You want customers to be able to enter host IPs that they control and your site will retrieve the URL on that site that they specify to confirm it's available.
You don't want customers to be able to request things like http://127.0.0.1:8080 or http://192.168.1.1:6443 as you've got internal systems running there that are not for external use.
So in your code you set the internal only ranges to be blocked.
If you used this library to do that, it would be possible to bypass the restriction and request internal IPs by using octal encoding, as the customer could enter an octal IP and then the conversion would allow for ranges that should be blocked, to be requested.
Thanks, that makes sense. I was thinking along the lines of applications interpreting HTTP headers like X-Forwarded-For, but trusting the client (instead of re-writing).
The problem is that for a very long time the IETF did not specify the textual syntax of IPv4 addresses, and the POSIX specification for parsing dotted quads is bonkers.
I think it is unfortunate that they fixed the bug by aligning with inet_aton()’s ancient foolish support for octal, instead of inet_pton()’s newer strict decimal syntax, forbidding leading zeroes.
Based on your comment, should we expect this vulnerability in comparable packages from other languages/communities? Or is this an NPM/JS maturity issue, i.e., “it’s not my fault, fix the spec.”?
It’s obscure enough that I would expect this bug to turn up elsewhere, even though it’s an example of a fundamental security risk of parsers that don’t accept the same syntax (http://langsec.org/), and IPv4 addresses are a specific instance of this risk that has been written about for years. (Tho usually the weirdness of inet_aton() is treated as quirky rather than dangerous.)
I like the twist in the vulnerability report, using differences between IPv4 parsers to get past protections against things like SSRF, which I don’t think is explicitly mentioned in the IETF draft and RFC that I linked to.
The random thing learned from the article, is that ping parses octal, and apparently also hexadecimal. So now I can do ping 0x7f.0x1 next time I want to show off.
Some people will use this to argue against dependencies or npm, but I would argue that this vulnerability is actually a great example of why those are good things.
The bug is caused by an esoteric IP address notation. Nearly everyone who would need this functionality would get the implementation wrong. In the exact same way the author of netmask did. However, netmask is now fixed and this bug will now no longer appear in any new implementation.
Even better: npm will start to give warnings about this vulnerable package and will provide a fix through npm audit. Everything that is maintained in a reasonable way, will now no longer have this vulnerability.
This is not a failure of dependencies or npm: this is an example why those are good things.
Well, technically it parsed right. /sbin/ping will similarly parse odd notation. To me the issue was with ancillary functions like isPrivateIp() using the unparsed ip text.
Packaging is fine for security as we see with maintained Linux distribution, the problem people have with NPM community is that you get a spider web of packages because instead of a big high quality standard library you have to use some random guys npm package or copy and paste some code from Stack Overflow. The solution would be that Google,Mozilla,Microsoft and Apple would do something productive for once and create such an (optional) standard library and good tools that would know to only build the used stuff in the final thing.
I agree with your point. I never saw a problem with dependencies until I worked on a system where security and reliability were very high priorities. Apparently, on a system like that you only use the official language libraries, a very very minimal set of auxiliary libraries (e.g. Google's Guava), and everything else you code up yourself, because you can't include anything your team can't audit. You could audit a third-party library, but extracting or writing just the parts you need and then auditing that is always less work. That way you're sort of in a world without a wider eco-system.
I think the really big issue with all these package management solutions is how deep the dependency requirements go. One package depends on another package that depends on 18 other packages, that depend on 30 other packages, and it's packages all the way down.
No one is going to review all of those packages regularly. It's just not going to happen. Sure, it's less a problem for the big popular packages, but those big popular packages still depend on a lot of smaller packages and those smaller packages are extremely vulnerable due to sheer lack of eyes on it.
Everyone always says "I won't use software that isn't open source because the code is in the open and vulnerabilities can be found" but the fact of the matter is someone has to be reviewing that code to find them. I'd love to better understand how many people are out there reviewing code as part of their process. I'll be it's a lot less than anyone would like.
The alternative is to develop the entire stack in house. Unlikely that you’ll do any better and meanwhile your competitors will pass you by.
It’s really just the consequence of asymmetrical outcomes. Most of the time it all just works and so if you don’t keep up you’re out of business. When something goes wrong the whole world is exposed.
I guess with npm you do have the additional wrinkle that much of it is outside the std lib which increases risk a bit.
> The alternative is to develop the entire stack in house
Maybe now because everyone is entrenched, but the alternative could have been to offer a robust "standard library" in the first place that lets you cover 90% of developer's use cases without needing external packages. See: Java, C/C++, Go, Python...
Only JavaScript seems to be a special snowflake where doing even the most basic tasks requires downloading 50 packages.
I'm not super familiar with the JS ecosystem, but isn't Node unique in that it tends to have packages for things that arguably have no business being their own dependencies? leftpad comes to mind.
JVM/Java has an extensive stdlib, including a decent DNS/IP resolution library that this package contains a vulnerability in.
It also has one of the best date/time libraries I've ever seen, while that it external in nearly all languages for example.
In your examples, only Java and Go have robust standard libraries and both are essentially corporate programming languages.
The claim that C has a safe and/or robust standard library is very bizarre. Python only got there after years of community development (Python is 30 years old, Node is 11), and even today I wouldn't consider it particularly high quality.
> The alternative is to develop the entire stack in house. Unlikely that you’ll do any better and meanwhile your competitors will pass you by.
First, you'd never develop everthing in house. But there is a middle ground between selecting a few very well known dependencies that are nowhere near practical to do in-house (e.g. OpenSSL) and the extreme of the npm world where every one-liner is a package.
Another great solution is to select a language with a rich well-tested standard library.
Rely on the standard library for 80% of your utility class needs. Complement with a small number of well-known external libraries for another 20% and the remaining 10% build in-house.
If one can't, off the top of their head, name every external dependency and where they come from, that's too many.
> The bug is caused by an esoteric IP address notation
Fun fact: there are even more IP address notations... try ping'ing 0x7F000001 or 2130706433, for example - on OS X commandline and Google Chrome at least, these resolve to localhost.
Many companies have auditing requirements for external dependencies, with increasing strictness for more sensitive domains.
It would be immensely helpful to distribute this effort.
We could have a platform that pays top domain experts and security researchers for audits. Companies can get access to via a subscription model or by paying for specific dependencies.
Vulnerabilities would also be reported and fixed, helping everyone, and companies benefit by having a trustworthy source for audits and save internal work.
Ideally the platform would be successful enough to open up a good amount of audits publicly to benefit the whole community.
Also related: cargo-crev [1] explores a concept for shared auditing and trust for Rust crates.
Either the bugs aren't reported to upstream and it remains vulnerable, or they are reported and get fixed, making paying to access the audit pointless. The first option would basically involve the platform maintaining a closed fork, which won't work with most licenses and would be terrible for the ecosystem.
As I said, many companies require a review/sign off for each dependency (version). Since they usually can't get them externally, they have do it internally.
Enterprises also throw a lot of money at support contracts they never use, there is absolutely space for auditing expenses that give assurance and will be more thorough than any internal process.
I'm really curious - has anyone ever worked somewhere where _all_ packages are _actually_ reviewed?
I'm pretty sure this really is a thing in some places (defense contractors, etc), but I'm curious if anyone's actually been exposed to a real company that really reviews everything.
Sidenote: whoever thought octal notation was useful, was, well, wrong. Can we just stop supporting it entirely? I mean, how much of the internet will break if octal IPv4 addresses would stop working? Or if `010` would stop compiling in C sources except if some --enable-octal flag were supplied?
IIUC, this is not exploitable in the more common setups where the IP address is being sourced from the inbound request. It's only an issue when the IP address itself is supplied by the user as text. Using something like the "ip" field on an inbound request would not be vulnerable.
First by the netmask function that reads 0127 as 127 and the second time by the js-network stack code that reads it differently.
The solution is not to change netmask to ignore leading zeros. The solution is to parse it into 4 uint8 values, validate the netblock on the numeric values and if the range is approved, generate the ip-address from your four numbers. That way you know for sure that the js-network stack is going to interpret it as you intend.
90 comments
[ 0.22 ms ] story [ 146 ms ] threadUnvetted code essentially marketed as an extended standard library.
[1] https://www.dreamsongs.com/WorseIsBetter.html
I'm sure there's businesses that would pay for a dependency provider that ensures all versions of all packages hosted there are reviewed, security checked and signed off on. With a warranty clause, so that if something like this does come out, they get compensated for damages (if actively exploited). A bug bounty should of course also be offered.
A bit like Apple's app store but for libraries. Or the ideal thereof anyway. Basically a library developer can't just keep spamming updates, they would have to be more careful with what they submit.
And of course, library devs would get a slice of the pie, an X amount per installation.
It probably wouldn't work because people (even large enterprises who cannot afford any security issue like this) prefer free.
The real problem is that the standard library of node/javascript is too small so you need dozens of packages for basic operations.
That would be Microsoft.
You get companies doing things like version checking and basic scans for malware, but that wouldn't catch issues like this.
My guess is that the volume of security review you'd need to do, for it to be usable by enough companies, is massive and a lot of the review would need to be manual.
Then as you add libraries you need to dedicate resources to reviewing every new release.
Do they do a one-time review, problem there is it won't catch new issues.
Do they provide PRs for fixing issues found, that's another level of complexity.
If the library owners don't patch promptly, do MS fork the lib, if they do, will people move to their forked version?
It's a complex area to say the least :)
It'd be great to see more companies take it on but I have a feeling it'll be a long time before we see significant coverage of this kind of issue.
I have the same feeling about PyPI, but to a way lesser extent. Python can already do much by itself, so that the amount of packages one installs is controllable.
Both are open-sourced and are written by pretty much the same people.
This of course depends on the library in question, as some non-std libraries are certainly subjected to more checks than others.
It's great to have high quality third party libraries but stuff like most of lodash should be in a stdlib, already.
https://pypi.org/simple/ (caution— multi-megabyte html)
https://docs.python.org/3.9/library/ipaddress.html#ipaddress...
But this is not an issue:
With many small libraries there often is a single person working on it and others assuming "oh, somebody will have reviewed it"
This can happen with a big library as well (as individual maintainers "own" specific parts) but there it is easier to establish a review culture.
(Whether a review would have caught this specific case is yet another question, but again having an organisation could guarantee a timely response, is read if depending on a single contributor)
Say you grab a 10 years old Java/.Net project source and a node one, and try to setup a developer environment to be able to create a fix. Would you bet that on average is 10X harder to get stuff to run on node ?
I think you’re being a little optimistic there.
Consider Java’s URL class, for instance. Its equals() implementation will resolve the hostname in both URLs and consider them equal if they resolve to the same IP address. So that’s a) completely wrong, b) a potential source of security problems (consider an attacker pointing their hostname to your IP address to control URLs that are “equal” to your URLs, for instance), c) horribly unpredictable (two URLs may or may not be the same depending on whether you are online or not), and d) awful for performance (introduces a network lookup even for hashcode(), for instance).
That’s significantly worse than a bug like this, which is essentially an oversight that failed to consider an obscure notation nobody uses.
> Say you grab a 10 years old Java/.Net project source and a node one, and try to setup a developer environment to be able to create a fix. Would you bet that on average is 10X harder to get stuff to run on node ?
Java is probably okay, but I’ve tried this with .NET and it was extremely painful.
I would bet that on average Java standard library code(that is not deprecated) will be higher quality then npm packages.
Bonus points for security scanners that diagnose grave vulnerabilities in frontend bundles but the backend is some Python/Ruby/guaranteed-no-npm API.
You want customers to be able to enter host IPs that they control and your site will retrieve the URL on that site that they specify to confirm it's available.
You don't want customers to be able to request things like http://127.0.0.1:8080 or http://192.168.1.1:6443 as you've got internal systems running there that are not for external use.
So in your code you set the internal only ranges to be blocked.
If you used this library to do that, it would be possible to bypass the restriction and request internal IPs by using octal encoding, as the customer could enter an octal IP and then the conversion would allow for ranges that should be blocked, to be requested.
The protection has to sit in the HTTP client library after resolving the hostname to IP address, before connecting.
The writeup at https://www.bleepingcomputer.com/news/security/critical-netm... has a link to an informative ancient expired IETF draft https://tools.ietf.org/html/draft-main-ipaddr-text-rep which describes how things stood in 2003.
A more recent and more official RFC from the IETF on the security implications of inconsistent parsers discusses the issue behind this CVE https://tools.ietf.org/html/rfc6943#section-3.1.1
The problem is that for a very long time the IETF did not specify the textual syntax of IPv4 addresses, and the POSIX specification for parsing dotted quads is bonkers.
I think it is unfortunate that they fixed the bug by aligning with inet_aton()’s ancient foolish support for octal, instead of inet_pton()’s newer strict decimal syntax, forbidding leading zeroes.
I like the twist in the vulnerability report, using differences between IPv4 parsers to get past protections against things like SSRF, which I don’t think is explicitly mentioned in the IETF draft and RFC that I linked to.
https://play.rust-lang.org/?version=stable&mode=debug&editio...
Report the issue in https://github.com/rust-lang/rust/issues/83648
The bug is caused by an esoteric IP address notation. Nearly everyone who would need this functionality would get the implementation wrong. In the exact same way the author of netmask did. However, netmask is now fixed and this bug will now no longer appear in any new implementation.
Even better: npm will start to give warnings about this vulnerable package and will provide a fix through npm audit. Everything that is maintained in a reasonable way, will now no longer have this vulnerability.
This is not a failure of dependencies or npm: this is an example why those are good things.
You must have a lot more "great examples" up your sleeve!
I think the really big issue with all these package management solutions is how deep the dependency requirements go. One package depends on another package that depends on 18 other packages, that depend on 30 other packages, and it's packages all the way down.
No one is going to review all of those packages regularly. It's just not going to happen. Sure, it's less a problem for the big popular packages, but those big popular packages still depend on a lot of smaller packages and those smaller packages are extremely vulnerable due to sheer lack of eyes on it.
Everyone always says "I won't use software that isn't open source because the code is in the open and vulnerabilities can be found" but the fact of the matter is someone has to be reviewing that code to find them. I'd love to better understand how many people are out there reviewing code as part of their process. I'll be it's a lot less than anyone would like.
It’s really just the consequence of asymmetrical outcomes. Most of the time it all just works and so if you don’t keep up you’re out of business. When something goes wrong the whole world is exposed.
I guess with npm you do have the additional wrinkle that much of it is outside the std lib which increases risk a bit.
Maybe now because everyone is entrenched, but the alternative could have been to offer a robust "standard library" in the first place that lets you cover 90% of developer's use cases without needing external packages. See: Java, C/C++, Go, Python...
Only JavaScript seems to be a special snowflake where doing even the most basic tasks requires downloading 50 packages.
Python is specifically known as a “batteries included” language, and Go has stdlib support for the core use cases the language is designed for.
I wouldn’t say that C++ or Java have particularly rich standard libraries outside of IO and common data structures, and C is downright anaemic.
The Java standard library is about as rich as it gets. I rarely ever have had to use external dependencies when working on Java projects.
The claim that C has a safe and/or robust standard library is very bizarre. Python only got there after years of community development (Python is 30 years old, Node is 11), and even today I wouldn't consider it particularly high quality.
First, you'd never develop everthing in house. But there is a middle ground between selecting a few very well known dependencies that are nowhere near practical to do in-house (e.g. OpenSSL) and the extreme of the npm world where every one-liner is a package.
Another great solution is to select a language with a rich well-tested standard library.
Rely on the standard library for 80% of your utility class needs. Complement with a small number of well-known external libraries for another 20% and the remaining 10% build in-house.
If one can't, off the top of their head, name every external dependency and where they come from, that's too many.
Fun fact: there are even more IP address notations... try ping'ing 0x7F000001 or 2130706433, for example - on OS X commandline and Google Chrome at least, these resolve to localhost.
Many companies have auditing requirements for external dependencies, with increasing strictness for more sensitive domains.
It would be immensely helpful to distribute this effort.
We could have a platform that pays top domain experts and security researchers for audits. Companies can get access to via a subscription model or by paying for specific dependencies.
Vulnerabilities would also be reported and fixed, helping everyone, and companies benefit by having a trustworthy source for audits and save internal work.
Ideally the platform would be successful enough to open up a good amount of audits publicly to benefit the whole community.
Also related: cargo-crev [1] explores a concept for shared auditing and trust for Rust crates.
[1] https://github.com/crev-dev/cargo-crev
As I said, many companies require a review/sign off for each dependency (version). Since they usually can't get them externally, they have do it internally.
Enterprises also throw a lot of money at support contracts they never use, there is absolutely space for auditing expenses that give assurance and will be more thorough than any internal process.
I'm pretty sure this really is a thing in some places (defense contractors, etc), but I'm curious if anyone's actually been exposed to a real company that really reviews everything.
Am I going crazy or is the `or` clause completely pointless?
I don't see it.
First by the netmask function that reads 0127 as 127 and the second time by the js-network stack code that reads it differently.
The solution is not to change netmask to ignore leading zeros. The solution is to parse it into 4 uint8 values, validate the netblock on the numeric values and if the range is approved, generate the ip-address from your four numbers. That way you know for sure that the js-network stack is going to interpret it as you intend.
There are some beautiful (horrifying) examples in this presentation: https://www.blackhat.com/docs/us-17/thursday/us-17-Tsai-A-Ne...