The popular npm netmask library recently encountered a serious problem, explained as follows:
The npm netmask package incorrectly evaluates individual ipv4 octets that contain octal strings as left-stripped integers, leading to an inordinate attack surface on hundreds of thousands of projects that rely on netmask to filter or evaluate ipv4 block ranges, both inbound and outbound.
In case you can’t read mumbo jumbo, hold on, and I’ll try to explain.
The npm library netmask is used by hundreds of thousands of applications and amasses over 3 million weekly downloads. It is used to read and manipulate IP addresses.
If you understand IP addresses and octals, you can skip the next section.
An IP address tells us how to find a certain device within a network. For each network a computer is connected to, it has an IP-address on that network. The IP address for this website is
126.96.36.199, for example.
Some things that happen inside a computer rely on an IP address too. For that we can use either
127.0.0.1, which is why that one is called “home” or “localhost”.
Domains, names used to address computers, are associated with IP-addresses. The Domain Name System (DNS) translates domain names used by people, like
blog.malwarebytes.com into the IP addresses used by computers, like
188.8.131.52. The DNS system is often compared to a phone book where you can look up a person’s name to find their phone number.
When you see an IP address you will probably recognize it for what it is. The typical format of an IP version 4 address is very familiar: Four numbers between 0 and 255 separated by three dots.
In fact, an IP address is a decimal representation of a 32-bit number. The 32-bit number is grouped 8 bits at a time, each group of 8 bits is an octet. The octets are separated by a dot, and represented in decimal format, this is known as dotted decimal notation. The possibilities range from
The difference between decimal and octal
Decimal means a number expressed in the base-ten system which is the system that we use every day that uses the digits 0 to 9, whereas octal means the number system that uses the eight digits 0, 1, 2, 3, 4, 5, 6, 7.
Since an IP address is a 32 bit number it makes a lot of sense to use the octal number system. In that system the dotted octal
127.0.0.1 looks like
0177.0000.0000.0001. Here’s why:
In decimal, numbers are written according to how many ones they have, how many tens, how many hundreds, and so on. So the number 127 is 1 * 100, 2 * 10 and 7 * 1.
In octal, numbers are written according to how many ones they have, how many eights, how many 64s, and so on. So the number 127 is represented as 0177, which is 0 * 128, 1 * 64, 7 * 8 and 7 * 1.
Using different numerical systems is no problem for computers, as long as it’s clear which one you are using. Allowing mixed input for an application is asking for problems, however.
The netmask vulnerability
To understand the problem it helps to understand how things are supposed to work, copy the octal IP address
0177.0000.0000.0001 into your browser address bar. It should get correctly translated to
127.0.0.1. And try
0184.108.40.206 in the same browser you used before. And act surprised when it still takes you to
127.0.0.1 despite the fact that we did not write out the last three octets in full.
0220.127.116.11 look like they are in the same notation but they are not. The first zero on
018.104.22.168 makes all the difference, and your browser knows this.
The problem with tnetmask was that it stripped leading zeroes from IP addresses. So, if you fed it an address that starts with a zero, like
0177.0000.0000.0001, it will not recognise it as an octal address and turn it into the decimal version,
127.0.0.1 like your browser. Instead it would treat it a decimal address,
22.214.171.124, which is an address for a completely different computer.
While this may seem more of an inconvenience than a security problem at first sight, but when an attacker is able to influence the IP address input being parsed by the application, the bug can give rise to various vulnerabilities.
Private IP or not?
Remember when I wrote that your computer has an IP address in every network it is connected to? Some IP address ranges are reserved for internal networks and can’t be used on the Internet. The most well-known is probably
192.168.1.255, often written as
192.168.1.xxx. Many home networks use the
10.0.1.xxx network range.
Importantly, many systems are set up to be more trusting towards traffic coming from inside a private network. See how that might pose a problem? If an attacker fed a vulnerable version of netmask the address
012.0.0.1, netmask would read it as the public address
126.96.36.199 instead of the private address
According to netmask’s own maintainer, the vulnerability could have allowed an attacker to abuse this trust and gain access to all kinds of things they shouldn’t:
A remote authenticated or unauthenticated attacker can bypass packages that rely on netmask to filter IP address blocks to reach intranets, VPNs, containers, adjacent VPC instances, or LAN hosts
Publicly disclosed computer security flaws are listed in the Common Vulnerabilities and Exposures (CVE) database. Its goal is to make it easier to share data across separate vulnerability capabilities (tools, databases, and services). This zero-day is listed as CVE-2021-28918.
The fix for CVE-2021-28918 has been released in version 2.0.1 of netmask on npm downloads. The Perl component Net::Netmask also suffered from this flaw, and its maintainer, Joelle Maslak has released a fix in the 2.0000 version today.
Stay safe, everyone!