Fixing CVE-2018-18751 vulnerability

An issue was discovered in GNU gettext 0.19.8. There is a double free in default_add_message in read-catalog.c, related to an invalid free in po_gram_parse in po-gram-gen.y, as demonstrated by lt-msgfmt.

This vulnerability was reported in NIST as CVE-2018-18751. According to its description, the gettext incorrectly handles certain messages. An attacker could possibly use this issue to execute arbitrary code. The recommendation here is to upgrade the underlying system in order to update gettext (latest release is 0.20.2).

At the first glance, it does't make much sense. How does upgrading the underlying system could possibly fix an issue with a library? Why do we need to upgrade an entire system rather than just the library itself?


I was working on a software Product which uses gettext to translate portable object files (*.po) to a JSON format. The project uses a variant of Zenika/alpine-chrome to build a Docker image. Basically, the GNU gettext library is installed onto the Alpine Linux OS (in this case it's alpine-chrome) used within the final Docker image.

In my analysis, I realized upgrading the gettext library to a minimum version as in apk add – no-cache "gettext>0.20.2" will not work. This is because the --no-cache option always does an apk update and then fetches latest gettext available. While building the baseline artifact, the Alpine 3.9 retrieves gettext-0.19.8.1-r4 by default. The gettext package is somehow interlinked with the Alpine Linux version. See below the Alpine package website references where each Linux version has an associated gettext package.

For Alpine 3.9, the gettext-0.19.8.1-r4

https://pkgs.alpinelinux.org/packages?name=gettext&branch=v3.9

From Alpine v3.11 onwards, gettext version changes from 0.20.1-r2 through the latest 0.20.2-r0

https://pkgs.alpinelinux.org/packages?name=gettext&branch=v3.11

I modified the command to install gettext in a project file as below, expecting it to install the latest gettext version:

Cmd("RUN", """echo @edge http://nl.alpinelinux.org/alpine/edge/community >> 
/etc/apk/repositories && echo @edge http://nl.alpinelinux.org/alpine/edge/main >> 
/etc/apk/repositories && apk add --no-cache gettext && rm -rf /var/cache/* && mkdir /var/cache/apk"""),

At present, edge is the most current Alpine Linux version available.

This approach to building Docker image resulted in below console log, where Alpine v3.9 picks up gettext 9.19.8.1-r4:

[info] fetch http://dl-cdn.alpinelinux.org/alpine/v3.9/main/x86_64/APKINDEX.tar.gz
[info] fetch http://nl.alpinelinux.org/alpine/edge/main/x86_64/APKINDEX.tar.gz
....
[info] (1/2) Installing libgomp (8.3.0-r0)
[info] (2/2) Installing gettext (0.19.8.1-r4)
[info] Executing busybox-1.29.3-r10.trigger
....

The Docker image was built successfully but it did not yield the expected result. This concludes that upgrading Alpine OS is the only option left to upgrade the gettext library. This is also inline with the recommended solution listed at the NIST website.


At this time, I was not sure if the Product really need the gettext library in the first place. In my initial analysis, I could not find a direct relationship between the library and the Product. The Product uses frontend libraries to internationalize the text displayed on the user interface. These libraries are in no way relying on the GNU gettext. They are more or less JavaScript ported versions of the actual GNU gettext library.

Later, when I built the Docker image for the Product I found that gettext is installed on Alpine OS. It was evident from the console log. This is a visual proof that gettext is used somewhere within the Product. Although, I am not still convinced that the Product uses gettext internally to translate text meant for the user interface. I was asking myself that how could translations at the presentation layer relate to the GNU gettext library?

Further analysis revealed that the project uses a shell script which uses msgcat and msginit. These are programs or utilities which are part of the GNU gettext library. For instance, the msginit is used to generate a Portable Object (*.po) file out of the Portal Object Template (*.pot) file. This confirms that the project indeed relies on the gettext library. This shell script is essentially used during the Docker building phase, which explains why we have the vulnerability in the first place.

Below is the output produced during the Docker build:

[info] Step 1/29 : FROM docker-registry/alpine-chrome:latest
....
....
[info] Step 7/29 : RUN apk add --no-cache gettext
....
[info] (1/3) Installing libgomp (9.2.0-r4)
[info] (2/3) Installing gettext-libs (0.20.1-r2)
[info] (3/3) Installing gettext (0.20.1-r2)
....
[info] Successfully tagged <docker-id>

Upgrade to alpine-chrome has finally upgraded gettext to 0.20.1-r2, fixing the CVE-2018-18751 vulnerability.

There were other vulnerabilities reported by JFrog Xray-scan for the Product:

PCRE2 before 10.30 has an out-of-bounds write caused by a stack-based buffer overflow in pcre2_match.c, related to a "pattern with very many captures."

This issue was reported as a high vulnerability for the latest alpine-chrome. It is most likely caused by the alpine-chrome itself. However, the Product had to ignore these issues as it is not simple to fix them. Fixing these issues involves modifying underlying dependencies and maintaining them. It is a cost which the Product team had to avoid. The Product already uses an upgraded and latest verion of alpine-chrome. The other vulnerabilities shall be resolved when a new Alpine version is available.

See below, the Xray scan report for alpine-chrome lists two high vulnerabilities.

CVE-2020-14155 - Libpcre in pcre before 8.44 allows an integer overflow via a large number after a (?c substring. CVE-2017-8399 - Pcre2 before 10.30 has an out-of-bounds write caused by a stack-based buffer overflow in pcre2_match.c, related to a "pattern with very many captures."