Cyber Security
The different flavours of Docker image security
This article focuses on outlining the difference between some of the common image security scanners out there, what they are scanning for, and what the major differences are.
This article focuses on outlining the difference between some of the common image security scanners out there, what they are scanning for, and what the major differences are.
Container security is on everyone’s lips. After creating the CoGuard-CLI, we were asked a lot about what it does, how it does it, and how it compares to or complements other tools. This article focuses on outlining the difference between some of the common image security scanners out there, what they are scanning for, and what the major differences are.
We have selected the following free or open source tools for this article:
To illustrate what each tool finds, we will be scanning the WordPress image.
The command run on Snyk was
snyk container test wordpress
Here is an excerpt of Snyk's findings
Testing wordpress...
[TRUNCATED HERE FOR THIS BLOG ARTICLE]
High severity vulnerability found in apache2/apache2-bin
Description: HTTP Request Smuggling
Info: https://snyk.io/vuln/SNYK-DEBIAN11-APACHE2-2863492
Introduced through: apache2@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-bin@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-data@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-utils@2.4.53-1~deb11u1
and 1 more...
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
Fixed in: 2.4.54-1~deb11u1
✗ High severity vulnerability found in apache2/apache2-bin
Description: Information Exposure
Info: https://snyk.io/vuln/SNYK-DEBIAN11-APACHE2-2863500
Introduced through: apache2@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-bin@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-data@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-utils@2.4.53-1~deb11u1
and 1 more...
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
Fixed in: 2.4.54-1~deb11u1
✗ Critical severity vulnerability found in openssl/libssl1.1
Description: OS Command Injection
Info: https://snyk.io/vuln/SNYK-DEBIAN11-OPENSSL-2933518
Introduced through: openssl/libssl1.1@1.1.1n-0+deb11u2, libzip/libzip4@1.7.3-1, apache2@2.4.53-1~deb11u1, ca-certificates@20210119
From: openssl/libssl1.1@1.1.1n-0+deb11u2
From: libzip/libzip4@1.7.3-1 > openssl/libssl1.1@1.1.1n-0+deb11u2
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-bin@2.4.53-1~deb11u1 > openssl/libssl1.1@1.1.1n-0+deb11u2
and 6 more...
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
Fixed in: 1.1.1n-0+deb11u3
✗ Critical severity vulnerability found in freetype/libfreetype6
Description: Out-of-bounds Write
Info: https://snyk.io/vuln/SNYK-DEBIAN11-FREETYPE-2774656
Introduced through: freetype/libfreetype6@2.10.4+dfsg-1, imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3, ghostscript@9.53.3~dfsg-7+deb11u2
From: freetype/libfreetype6@2.10.4+dfsg-1
From: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3 > freetype/libfreetype6@2.10.4+dfsg-1
From: ghostscript@9.53.3~dfsg-7+deb11u2 > ghostscript/libgs9@9.53.3~dfsg-7+deb11u2 > freetype/libfreetype6@2.10.4+dfsg-1
and 1 more...
Image layer: 'apt-get install -y --no-install-recommends ghostscript'
Fixed in: 2.10.4+dfsg-1+deb11u1
✗ Critical severity vulnerability found in apache2/apache2-bin
Description: Insufficient Verification of Data Authenticity
Info: https://snyk.io/vuln/SNYK-DEBIAN11-APACHE2-2863474
Introduced through: apache2@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-bin@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-data@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-utils@2.4.53-1~deb11u1
and 1 more...
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
Fixed in: 2.4.54-1~deb11u1
✗ Critical severity vulnerability found in apache2/apache2-bin
Description: Integer Overflow or Wraparound
Info: https://snyk.io/vuln/SNYK-DEBIAN11-APACHE2-2863497
Introduced through: apache2@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-bin@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-data@2.4.53-1~deb11u1
From: apache2@2.4.53-1~deb11u1 > apache2/apache2-utils@2.4.53-1~deb11u1
and 1 more...
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
Fixed in: 2.4.54-1~deb11u1
✗ Critical severity vulnerability found in aom/libaom0
Description: Release of Invalid Pointer or Reference
Info: https://snyk.io/vuln/SNYK-DEBIAN11-AOM-1290331
Introduced through: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3
From: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3 > libheif/libheif1@1.11.0-1 > aom/libaom0@1.0.0.errata1-3
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
✗ Critical severity vulnerability found in aom/libaom0
Description: Use After Free
Info: https://snyk.io/vuln/SNYK-DEBIAN11-AOM-1298721
Introduced through: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3
From: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3 > libheif/libheif1@1.11.0-1 > aom/libaom0@1.0.0.errata1-3
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
✗ Critical severity vulnerability found in aom/libaom0
Description: Buffer Overflow
Info: https://snyk.io/vuln/SNYK-DEBIAN11-AOM-1300249
Introduced through: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3
From: imagemagick/libmagickcore-6.q16-6@8:6.9.11.60+dfsg-1.3 > libheif/libheif1@1.11.0-1 > aom/libaom0@1.0.0.errata1-3
Image layer: Introduced by your base image (wordpress:6.0.0-php7.4-apache)
Organization: albert.heinle
Package manager: deb
Project name: docker-image|wordpress
Docker image: wordpress
Platform: linux/amd64
Base image: wordpress:6.0.0-php7.4-apache
Licenses: enabled
Tested 237 dependencies for known issues, found 211 issues.
Base Image Vulnerabilities Severity
wordpress:6.0.0-php7.4-apache 211 7 critical, 10 high, 3 medium, 191 low
Recommendations for base image upgrade:
Alternative image types
Base Image Vulnerabilities Severity
wordpress:6.0-php8.1-fpm 191 5 critical, 6 high, 2 medium, 178 low
wordpress:php8.0-fpm 191 5 critical, 6 high, 2 medium, 178 low
wordpress:6.0-fpm 192 5 critical, 6 high, 2 medium, 179 low
wordpress:php8.1-apache 210 7 critical, 10 high, 3 medium, 190 low
Learn more: https://docs.snyk.io/products/snyk-container/getting-around-the-snyk-container-ui/base-image-detection
Interpretation
Snyk, known for its powerful code-scanning capabilities, is pointing out issues it found in the code of open source projects included in your image file. Snyk also includes CVE issues. If there is a fix available, the scanner points out which version to install. At the end, there are also alternative images recommended, which may or may not have less potential issues.
The command used was
docker run aquasec/trivy image wordpress
The output is well organized in a table, and looks like the following
wordpress (debian 11.3)
=======================
Total: 568 (UNKNOWN: 6, LOW: 336, MEDIUM: 113, HIGH: 93, CRITICAL: 20)
┌───────────────────────────┬──────────────────┬──────────┬───────────────────────┬───────────────────────┬──────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │
├───────────────────────────┼──────────────────┼──────────┼───────────────────────┼───────────────────────┼──────────────────────────────────────────────────────────────┤
│ apache2 │ CVE-2022-28615 │ CRITICAL │ 2.4.53-1~deb11u1 │ 2.4.54-1~deb11u1 │ httpd: out-of-bounds read in ap_strcmp_match() │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-28615 │
├───────────────────────────┼──────────────────┼──────────┼───────────────────────┼───────────────────────┼──────────────────────────────────────────────────────────────┤
│ apache2 │ CVE-2022-31813 │ CRITICAL │ 2.4.53-1~deb11u1 │ 2.4.54-1~deb11u1 │ httpd: mod_proxy: X-Forwarded-For dropped by hop-by-hop │
│ │ │ │ │ │ mechanism │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-31813 │
├───────────────────────────┼──────────────────┼──────────┼───────────────────────┼───────────────────────┼──────────────────────────────────────────────────────────────┤
│ apache2 │ CVE-2022-26377 │ HIGH │ 2.4.53-1~deb11u1 │ 2.4.54-1~deb11u1 │ httpd: mod_proxy_ajp: Possible request smuggling │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-26377 │
│ ├──────────────────┤ │ │ ├──────────────────────────────────────────────────────────────┤
│ │ CVE-2022-29404 │ │ │ │ httpd: mod_lua: DoS in r:parsebody │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-29404 │
│ ├──────────────────┤ │ │ ├──────────────────────────────────────────────────────────────┤
│ │ CVE-2022-30522 │ │ │ │ httpd: mod_sed: DoS vulnerability │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-30522 │
│ ├──────────────────┤ │ │ ├──────────────────────────────────────────────────────────────┤
│ │ CVE-2022-30556 │ │ │ │ httpd: mod_lua: Information disclosure with websockets │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-30556 │
│ ├──────────────────┼──────────┤ │ ├──────────────────────────────────────────────────────────────┤
│ │ CVE-2022-28614 │ MEDIUM │ │ │ httpd: out-of-bounds read via ap_rwrite() │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2022-28614 │
├───────────────────────────┼──────────────────┼──────────┼───────────────────────┼───────────────────────┼──────────────────────────────────────────────────────────────┤
│ apache2 │ CVE-2001-1534 │ LOW │ 2.4.53-1~deb11u1 │ │ mod_usertrack in Apache 1.3.11 through 1.3.20 generates │
│ │ │ │ │ │ session ID's u ... │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2001-1534 │
│ ├──────────────────┤ │ ├───────────────────────┼──────────────────────────────────────────────────────────────┤
│ │ CVE-2003-1307 │ │ │ │ ** DISPUTED ** The mod_php module for the Apache HTTP │
│ │ │ │ │ │ Server... │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2003-1307 │
│ ├──────────────────┤ │ ├───────────────────────┼──────────────────────────────────────────────────────────────┤
│ │ CVE-2003-1580 │ │ │ │ The Apache HTTP Server 2.0.44, when DNS resolution is │
│ │ │ │ │ │ enabled for clie... │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2003-1580 │
│ ├──────────────────┤ │ ├───────────────────────┼──────────────────────────────────────────────────────────────┤
│ │ CVE-2003-1581 │ │ │ │ httpd: Injection of arbitrary text into log files when DNS │
│ │ │ │ │ │ resolution is... │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2003-1581 │
├───────────────────────────┼──────────────────┼──────────┼───────────────────────┼───────────────────────┼──────────────────────────────────────────────────────────────┤
We truncated the other outputs.
Trivy appears to capture installed libraries on the image, and maps them to known items in the CVE database.
The command to run Grype on the wordpress image was
docker run anchore/grype wordpress
The output is also organized in a table.
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-29404 High
apache2 2.4.53-1~deb11u1 deb CVE-2001-1534 Negligible
apache2 2.4.53-1~deb11u1 deb CVE-2003-1580 Negligible
apache2 2.4.53-1~deb11u1 deb CVE-2003-1581 Negligible
apache2 2.4.53-1~deb11u1 deb CVE-2007-3303 Negligible
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-31813 Critical
apache2 2.4.53-1~deb11u1 deb CVE-2007-1743 Negligible
apache2 2.4.53-1~deb11u1 deb CVE-2008-0456 Negligible
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-30522 High
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-28615 Critical
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-26377 High
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-28614 Medium
apache2 2.4.53-1~deb11u1 deb CVE-2003-1307 Negligible
apache2 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-30556 High
apache2 2.4.53-1~deb11u1 deb CVE-2007-0086 Negligible
apache2-bin 2.4.53-1~deb11u1 deb CVE-2007-3303 Negligible
apache2-bin 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-30522 High
apache2-bin 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-30556 High
apache2-bin 2.4.53-1~deb11u1 deb CVE-2008-0456 Negligible
apache2-bin 2.4.53-1~deb11u1 deb CVE-2007-0086 Negligible
apache2-bin 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-28614 Medium
apache2-bin 2.4.53-1~deb11u1 deb CVE-2003-1307 Negligible
apache2-bin 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-29404 High
apache2-bin 2.4.53-1~deb11u1 deb CVE-2003-1580 Negligible
apache2-bin 2.4.53-1~deb11u1 deb CVE-2001-1534 Negligible
apache2-bin 2.4.53-1~deb11u1 2.4.54-1~deb11u1 deb CVE-2022-31813 Critical
apache2-bin 2.4.53-1~deb11u1 deb CVE-2003-1581 Negligible
The output is being truncated for this article.
Grype seems to do the same thing as Trivy, namely capture installed libraries on the image, and map them to known items in the CVE database. The number of issues found are also almost identical.
The command to run CoGuard was
coguard docker-image wordpress
The output captured was:
Scan result_jsons: 20 checks failed, 13 High/5 Medium/2 Low
X Severity 5: apache_deny_root_directory
Documentation: Ensure that the root directory access is specifically denied. Otherwise, it is possible that an attacker can
gain access to files through root directory mapping. Remediation: Create a Require all denied
directive Source:https://httpd.apache.org/docs/2.4/mod/core.html#directory
X Severity 5: apache_root_directory_options_none
Documentation: With the options directive, one can allow scripts to be executed, follow symlinks, do content negotiation, etc.
In the root directory, the Options directive should always be set to None. Remediation: Create a
Options None directive Source:https://httpd.apache.org/docs/2.4/mod/core.html#directory
X Severity 5: apache_enable_ssl
Documentation: We should never have any communication done using unencrypted channels. This check tests if the mod_ssl.so
module is loaded and that SSLProtocol is set, together with a proper SSL certificate file and a key file.
Remediation: Load the `mod_ssl.so` modules, and set the `SSLCertificateFile` and `SSLCertificateKeyFile` keys to
the paths of the respective certificate and key file.
X Severity 5: apache_load_logging_module
Documentation: Logging is important to monitor the activity on the server and detect anomalies. Remediation: Load the module
`mod_log_config` module in the configuration Source: https://httpd.apache.org/docs/2.4/mod/mod_log_config.html
X Severity 5: apache_load_security_module
Documentation: ModSecurity is a module that acts as a web application firewall for monitoring, logging, and access control. It
should always be loaded and configured Remediation steps: Load the module by adding `LoadModule security2_module
modules/mod_security2.so` Source: https://www.modsecurity.org/download.html
X Severity 4: dockerfile_last_user_should_be_non_root
Documentation: When creating a docker container, it is possible to set the user who is actually running the application and any
command on the container. It is important to specifically use the `USER` directive in any Dockerfile to ensure
that the user is not root and has unnecessary privileges. Remediation: Have at least one `USER` directive in
your Dockerfile, and the last user directive should not reference the root user or root group. Source:
https://docs.docker.com/engine/reference/builder/#user
X Severity 4: apache_content_security_policy_set
Documentation: One of the most effective techniques to prevent cross site scripting attacks is to control where the content is
served from. This can be achieved by setting specific policies in the `Content-Security-Policy` header.
Remediation: The value of that header is completely up to the specific web service. In order to pass this check,
the `httpd.conf` needs to contain a line of the form `Header always append Content-Security-Policy ` Source: https://wiki.owasp.org/index.php/OWASP_Secure_Headers_Project#csp
X Severity 4: apache_hsts_header_set
Documentation: There is an HTTP response header that instructs the browser to only communicate with the website using HTTPS,
the so called HSTS header. This one should be enabled. Remediation: Apache can automatically set this header
for every response by setting `Header always append Strict-Transport-Security "max-age:;
includeSubdomains"`` Source: https://wiki.owasp.org/index.php/OWASP_Secure_Headers_Project#hsts
X Severity 4: apache_run_as_separate_user
Documentation: Apache should not be run as root. In fact, it is best to configure the user it is run as. Remediation: Set the
`User` and `Group` directives to any user but `root`. Source:
https://httpd.apache.org/docs/2.4/mod/mod_unixd.html
X Severity 4: apache_turn_trace_off
Documentation: It is considered best practice to have tracing disabled for Apache HTTP servers. Remediation: Set `TraceEnable`
to `off` in your configuration Source: https://owasp.org/www-community/attacks/Cross_Site_Tracing
X Severity 4: apache_x_content_type_header_set
Documentation: There is an HTTP response header that disables the functionality of the browser to detect a content type
automatically, which poses an attack vector. Remediation: Apache can automatically set this header for every
response by setting `Header always append X-Content-Type-Options "nosniff" ` Source:
https://wiki.owasp.org/index.php/OWASP_Secure_Headers_Project#xcto
X Severity 4: apache_x_frame_options_same_origin
Documentation: There is an HTTP response header that makes it harder to do clickjacking. Apache can automatically set this
header for every response by setting `Header always append X-Frame-Options SAMEORIGIN` Source:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
X Severity 4: apache_x_xss_protection_set
Documentation: There is an HTTP response header that stops pages from loading in modern browsers when reflected cross site
scripting attacks are detected. Remediation: Apache can automatically set this header for every response by
setting `Header always append X-XSS-Protection "1; mode=block"` Source:
https://wiki.owasp.org/index.php/OWASP_Secure_Headers_Project#xxxsp
X Severity 3: apache_no_directory_listing
Documentation: When a user puts in a URL to a directory, the contents should not be listed. This may reveal files which the
hoster does not want the user to know about. Remediation: In each directive, set Options to None or
-Indexes. Source: http://httpd.apache.org/docs/current/mod/core.html#directory
X Severity 3: apache_deny_anything_older_than_http_1_1
Documentation: Many malicious programs will try to send arbitrary requests to your Apache web server. It is important to only
allow HTTP 1.1 requests, since support for older versions is obsolete. Remediation: Use the Rewrite engine
module of Apache to filter out requests. Add the following lines: RewriteEngine On RewriteCond %{THE_REQUEST}
!HTTP/1\.1$ RewriteRule .* - [F] Source:http://httpd.apache.org/docs/current/mod/mod_rewrite.html
X Severity 3: apache_restrict_ssl_protocol
Documentation: SSL 2.0, 3.0, TLS 1, 1.1 have reportedly several crytographic flaws. Hence, only TLS 1.2 should be used
Remediation: Set `SSLProtocol` to `-ALL +TLSv1.2`
X Severity 3: apache_server_tokens_off
Documentation: Even when a user gets to an error page, there should never be more information than necessary displayed on the
page. By not knowing the specific Apache HTTPd version, an attacker cannot match known issues to a certain
attack. Remediation: Set `ServerTokens` to `Prod` or `ProductOnly` in your configuration. Source:
https://httpd.apache.org/docs/2.4/mod/core.html#servertokens
X Severity 3: dockerfile_create_volume_for_var_log
Documentation: In linux systems, important operating system logs are stored in the `/var/log` subfolder. This folder should
always be made available to the host through a volume, so that log tracking and log analysis systems can capture
them. Remediation: In every Dockerfile, there should be a VOLUME directive which has `/var/log` as an
argument. Source: https://docs.docker.com/engine/reference/builder/
X Severity 2: apache_set_directory_options_none
Documentation: It is recommended to keep the Options for directives as restrictive as possible, and only set
Options not to None if really intended Remediation: In every directive, set `Options` to be `none`.
Source: https://httpd.apache.org/docs/2.4/mod/core.html#directory
X Severity 2: dockerfile_container_healthcheck_parameter
Documentation: Dockerfiles have an instruction called `HEALTHCHECK`. It enables a user to define a command to figure out if the
program(s) running inside the container are working properly. It is generally advisable to have healthchecks in
place to assist monitoring of running containers. Remediation: Have at least one `HEALTHCHECK` instruction in
your Dockerfile. Source: https://docs.docker.com/engine/reference/builder/#healthcheck
CoGuard detected that Apache was installed on the system, and extracted the configuration file. Security and best practice recommendations were produced based on the contents of the found configuration file. In addition, it also checked the last Dockerfile used to create the image for common mistakes.
The following table summarizes the findings and differences between each of the scanners:
Trivy and Grype can be seen as equivalent tools, which are the best in class to identify and map installed software to CVEs.
Snyk has run its static analyzer against many major open source projects, and can produce the issues it found by version. The scanner keeps track of versions where potential issues are fixed.
CoGuard’s CLI is detecting configuration files inside the container, and scans them for security and best practice violations.
Summarizing: In order to get a full view on the security of your Docker image, you should use both Snyk and CoGuard, and also either Trivy or Grype, as the latter are equivalent.
CoGuard's CLI: https://github.com/coguardio/coguard-cli
Snyk: https://snyk.io/
Trivy: https://aquasecurity.github.io/trivy/v0.29.2/
Grype: https://github.com/anchore/grype
Check out and explore a test environment to run infra audits on sample repositories of web applications and view select reports on CoGuard's interative dashboard today.