Compare commits

...

24 Commits

Author SHA1 Message Date
Teppei Fukuda
073b315737 No error on unsupported OS (#40) 2019-05-21 09:24:45 +09:00
Nicolas CARPi
47c46fbe17 Fix some typos in the README or improve phrasing (#38)
also add .circleci to .dockerignore
2019-05-21 08:59:16 +09:00
mitsuyoshi
39572968bb fixed cache bug (#36) 2019-05-21 01:03:33 +09:00
Nao YONASHIRO
4383764cae fix: unknown format case (#35) 2019-05-21 00:17:44 +09:00
Kirill Motkov
e0ef0563ce Some code improvements. (#34)
* Rewrite some if-else chains as a switch statements. Based on Go style
guide: https://golang.org/doc/effective_go.html#switch
* Simplify some functions.
* Some comments formatting.
2019-05-21 00:17:18 +09:00
Teppei Fukuda
d9cf2c487d Update JSON schema (#33)
* Update JSON schema

* Add JSON example to README
2019-05-20 22:43:28 +09:00
Tomoya Amachi
58bf4b21e7 Merge pull request #32 from tomoyamachi/fix_quiet_bug
fix --quiet bug
2019-05-20 07:22:08 +09:00
Tomoya AMACHI
e95c619eaa fix quiet bug 2019-05-20 06:51:31 +09:00
knqyf263
cd04c0bdb2 Update README 2019-05-20 03:55:40 +09:00
Masahiro
fd74926e76 Change README. Use latest trivy version CI example. (#31) 2019-05-20 03:27:47 +09:00
Masahiro
f82ff5a4fd Change log format (#30) 2019-05-20 02:54:41 +09:00
Masahiro
fa72bef8d4 Add auto-refresh option (#29)
* Add auto-refresh option

* Fix review
2019-05-20 02:00:35 +09:00
Masahiro
2f7f1f8e83 Change Dockerfile (#28)
* Change Dockerfile CMD -> ENTRYPOINT

* Change README
2019-05-19 09:54:18 +09:00
Teppei Fukuda
90d083489b Enable --clear-cache and --refresh without specifying an image name (#27) 2019-05-19 08:52:56 +09:00
Teppei Fukuda
295cd29aeb Suppress the warning message when specifying --clear-cache option (#25) 2019-05-19 00:17:44 +09:00
Tomoya Amachi
1c844aad64 show scanned os type if unsupported (#24) 2019-05-18 22:47:55 +09:00
Sandro Jäckel
e0cd18e264 [ImgBot] Optimize images (#22)
*Total -- 1,372.59kb -> 661.35kb (51.82%)

/imgs/usage2.png -- 490.56kb -> 214.83kb (56.21%)
/imgs/usage1.png -- 652.71kb -> 314.83kb (51.77%)
/imgs/centos_include_unfixable.png -- 74.40kb -> 40.77kb (45.2%)
/imgs/alpine.png -- 67.03kb -> 37.37kb (44.26%)
/imgs/centos_only_fixable.png -- 73.59kb -> 43.73kb (40.58%)
/imgs/logo.png -- 14.29kb -> 9.83kb (31.24%)
2019-05-18 22:38:55 +09:00
Sandro Jäckel
9f9faf2215 Suggest putting the apt source in its own file (#21) 2019-05-18 22:36:53 +09:00
knqyf263
3907a60b33 Update README 2019-05-17 19:03:28 +09:00
Naoki Harima
e85e961af6 Update fanal version (#15)
* Update fanal version

* Update fanal version

* do go mod tidy
2019-05-17 19:00:22 +09:00
0xflotus
61cbae2697 fixed provided (#14) 2019-05-17 17:57:27 +09:00
Ken Herner
2d512c5e47 Allow user specified cache directory (#12)
* Added cache-dir flag

The flag cache-dir allows users to specify the cache directory the
database is stored in.

Signed-off-by: Ken Herner <kherner@navistone.com>

* Moved dbDir definition into functions

Need to move dbDir definition into the calling functions as the cache
directory may have been specified.  With dbDir defined at package level,
it would always be instantiated to the default value and would never be
updated to the user specifyed value.

Signed-off-by: Ken Herner <kherner@navistone.com>
2019-05-17 07:13:43 +09:00
knqyf263
936297a6b2 Fix License badge 2019-05-17 07:12:15 +09:00
knqyf263
ad0f9e8cba Update README 2019-05-16 23:25:46 +09:00
22 changed files with 773 additions and 194 deletions

View File

@@ -1 +1,2 @@
.circleci
imgs

View File

@@ -11,4 +11,4 @@ RUN apk --no-cache add ca-certificates git
COPY --from=builder /trivy /usr/local/bin/trivy
RUN chmod +x /usr/local/bin/trivy
CMD ["trivy"]
ENTRYPOINT ["trivy"]

714
README.md
View File

@@ -3,12 +3,16 @@
[![GitHub release](https://img.shields.io/github/release/knqyf263/trivy.svg)](https://github.com/knqyf263/trivy/releases/latest)
[![CircleCI](https://circleci.com/gh/knqyf263/trivy.svg?style=svg)](https://circleci.com/gh/knqyf263/trivy)
[![Go Report Card](https://goreportcard.com/badge/github.com/knqyf263/trivy)](https://goreportcard.com/report/github.com/knqyf263/trivy)
[![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://github.com/knqyf263/trivy/blob/master/LICENSE)
[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
A Simple and Comprehensive Vulnerability Scanner for Containers, Compatible with CI
A Simple and Comprehensive Vulnerability Scanner for Containers, Suitable for CI
<img src="imgs/usage.gif" width="700">
<img src="imgs/usage1.png" width="600">
<img src="imgs/usage2.png" width="600">
# Accuracy Comparison
The number of vulnerabilities detected on Alpine Linux (as of 2019/05/12)
@@ -28,6 +32,8 @@ See [Comparison with other scanners](#comparison-with-other-scanners) for detail
- [Binary (Including Windows)](#binary-including-windows)
- [From source](#from-source)
- [Quick Start](#quick-start)
- [Basic](#basic)
- [Docker](#docker)
- [Examples](#examples)
- [Scan an image](#scan-an-image)
- [Scan an image file](#scan-an-image-file)
@@ -48,9 +54,10 @@ See [Comparison with other scanners](#comparison-with-other-scanners) for detail
- [Usage](#usage)
- [Comparison with other scanners](#comparison-with-other-scanners)
- [Overview](#overview)
- [vs Clair, Quay](#vs-clair-quay)
- [Accuracy](#accuracy)
- [vs Clair](#vs-clair)
- [vs Anchore Engine](#vs-anchore-engine)
- [vs Docker Hub, GCR](#vs-docker-hub-gcr)
- [vs Quay, Docker Hub, GCR](#vs-quay-docker-hub-gcr)
- [Q&A](#qa)
- [Homebrew](#homebrew)
- [Others](#others)
@@ -59,7 +66,7 @@ See [Comparison with other scanners](#comparison-with-other-scanners) for detail
`Trivy` (`tri` pronounced like **tri**gger, `vy` pronounced like en**vy**) is a simple and comprehensive vulnerability scanner for containers.
`Trivy` detects vulnerabilities of OS packages (Alpine, RHEL, CentOS, etc.) and application dependencies (Bundler, Composer, npm, yarn etc.).
`Trivy` is easy to use. Just install the binary and you're ready to scan. All you need to do for scanning is to specify a container image name.
`Trivy` is easy to use. Just install the binary and you're ready to scan. All you need to do for scanning is to specify an image name of container.
It is considered to be used in CI. Before pushing to a container registry, you can scan your local container image easily.
See [here](#continuous-integration-ci) for details.
@@ -71,14 +78,15 @@ See [here](#continuous-integration-ci) for details.
- **Application dependencies** (Bundler, Composer, Pipenv, npm, yarn and Cargo)
- Simple
- Specify only an image name
- See [Quick Start](#quick-start) and [Examples](#examples)
- Easy installation
- **No need for prerequirements** such as installation of DB, libraries, etc.
- `apt-get install`, `yum install` and `brew install` is possible (See [Installation](#installation))
- High accuracy
- **Especially Alpine Linux and RHEL/CentOS** (See [Comparison with other scanners](#comparison-with-other-scanners))
- Other OSes are also high
- Continuous Integration
- **Compatible with CI** such as Travis CI, CircleCI, Jenkins, etc.
- DevSecOps
- **Suitable for CI** such as Travis CI, CircleCI, Jenkins, etc.
- See [CI Example](#continuous-integration-ci)
# Installation
@@ -101,7 +109,7 @@ $ sudo yum -y install trivy
or
```
$ rpm -ivh https://github.com/knqyf263/trivy/releases/download/v0.0.12/trivy_0.0.12_Linux-64bit.rpm
$ rpm -ivh https://github.com/knqyf263/trivy/releases/download/v0.0.15/trivy_0.0.15_Linux-64bit.rpm
```
## Debian/Ubuntu
@@ -113,7 +121,7 @@ CODE_NAME: wheezy, jessie, stretch, buster, trusty, xenial, bionic
```
$ sudo apt-get install apt-transport-https gnupg
$ wget -qO - https://knqyf263.github.io/trivy-repo/deb/public.key | sudo apt-key add -
$ echo deb https://knqyf263.github.io/trivy-repo/deb [CODE_NAME] main | sudo tee -a /etc/apt/sources.list
$ echo deb https://knqyf263.github.io/trivy-repo/deb [CODE_NAME] main | sudo tee -a /etc/apt/sources.list.d/trivy.list
$ sudo apt-get update
$ sudo apt-get install trivy
```
@@ -122,13 +130,13 @@ or
```
$ sudo apt-get install rpm
$ wget https://github.com/knqyf263/trivy/releases/download/v0.0.12/trivy_0.0.12_Linux-64bit.deb
$ sudo dpkg -i trivy_0.0.12_Linux-64bit.deb
$ wget https://github.com/knqyf263/trivy/releases/download/v0.0.15/trivy_0.0.15_Linux-64bit.deb
$ sudo dpkg -i trivy_0.0.15_Linux-64bit.deb
```
## Mac OS X / Homebrew
You can use homebrew on OS X.
You can use homebrew on Mac OS.
```
$ brew tap knqyf263/trivy
@@ -137,7 +145,7 @@ $ brew install knqyf263/trivy/trivy
## Binary (Including Windows)
Go to [the releases page](https://github.com/knqyf263/trivy/releases), find the version you want, and download the zip file. Unpack the zip file, and put the binary to somewhere you want (on UNIX-y systems, /usr/local/bin or the like). Make sure it has execution bits turned on.
Get the latest version from [this page](https://github.com/knqyf263/trivy/releases/latest), and download the archive file for your operating system/architecture. Unpack the archive, and put the binary somewhere in your `$PATH` (on UNIX-y systems, /usr/local/bin or the like). Make sure it has execution bits turned on.
You need to install `rpm` command for scanning RHEL/CentOS.
@@ -147,11 +155,12 @@ You need to install `rpm` command for scanning RHEL/CentOS.
$ go get -u github.com/knqyf263/trivy
```
# Quick Start
Simply specify an image name (and a tag). **The `latest` tag should be avoided as problems occur with cache.**. See [Clear image caches](#clear-image-caches)
## Basic
```
$ trivy [YOUR_IMAGE_NAME]
```
@@ -159,16 +168,7 @@ $ trivy [YOUR_IMAGE_NAME]
For example:
```
$ trivy python:3.7-alpine
```
# Examples
### Scan an image
Simply specify an image name (and a tag).
```
$ trivy python:3.7-alpine
$ trivy python:3.4-alpine
```
<details>
@@ -192,6 +192,264 @@ Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
</details>
## Docker
Replace [YOUR_CACHE_DIR] with the cache directory on your machine.
```
$ docker run -v [YOUR_CACHE_DIR]:/root/.cache/ knqyf263/trivy [YOUR_IMAGE_NAME]
```
Example for macOS:
```
$ docker run -v $HOME/Library/Caches:/root/.cache/ knqyf263/trivy python:3.4-alpine
```
If you would like to scan the image on your host machine, you need to mount `docker.sock`.
```
$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v $HOME/Library/Caches:/root/.cache/ knqyf263/trivy python:3.4-alpine
```
<details>
<summary>Result</summary>
```
2019-05-16T01:20:43.180+0900 INFO Updating vulnerability database...
2019-05-16T01:20:53.029+0900 INFO Detecting Alpine vulnerabilities...
python:3.4-alpine3.9 (alpine 3.9.2)
===================================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| openssl | CVE-2019-1543 | MEDIUM | 1.1.1a-r1 | 1.1.1b-r1 | openssl: ChaCha20-Poly1305 |
| | | | | | with long nonces |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
```
</details>
# Examples
### Scan an image
Simply specify an image name (and a tag).
```
$ trivy knqyf263/test-image:1.2.3
```
<details>
<summary>Result</summary>
```
2019-05-16T12:58:55.967+0900 INFO Updating vulnerability database...
2019-05-16T12:59:03.150+0900 INFO Detecting Alpine vulnerabilities...
2019-05-16T12:59:03.156+0900 INFO Updating bundler Security DB...
2019-05-16T12:59:04.941+0900 INFO Detecting bundler vulnerabilities...
2019-05-16T12:59:04.942+0900 INFO Updating cargo Security DB...
2019-05-16T12:59:05.967+0900 INFO Detecting cargo vulnerabilities...
2019-05-16T12:59:05.967+0900 INFO Updating composer Security DB...
2019-05-16T12:59:07.834+0900 INFO Detecting composer vulnerabilities...
2019-05-16T12:59:07.834+0900 INFO Updating npm Security DB...
2019-05-16T12:59:10.285+0900 INFO Detecting npm vulnerabilities...
2019-05-16T12:59:10.285+0900 INFO Updating pipenv Security DB...
2019-05-16T12:59:11.487+0900 INFO Detecting pipenv vulnerabilities...
knqyf263/test-image:1.2.3 (alpine 3.7.1)
========================================
Total: 26 (UNKNOWN: 0, LOW: 3, MEDIUM: 16, HIGH: 5, CRITICAL: 2)
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| curl | CVE-2018-14618 | CRITICAL | 7.61.0-r0 | 7.61.1-r0 | curl: NTLM password overflow |
| | | | | | via integer overflow |
+ +------------------+----------+ +---------------+----------------------------------+
| | CVE-2018-16839 | HIGH | | 7.61.1-r1 | curl: Integer overflow leading |
| | | | | | to heap-based buffer overflow in |
| | | | | | Curl_sasl_create_plain_message() |
+ +------------------+ + +---------------+----------------------------------+
| | CVE-2019-3822 | | | 7.61.1-r2 | curl: NTLMv2 type-3 header |
| | | | | | stack buffer overflow |
+ +------------------+ + +---------------+----------------------------------+
| | CVE-2018-16840 | | | 7.61.1-r1 | curl: Use-after-free when |
| | | | | | closing "easy" handle in |
| | | | | | Curl_close() |
+ +------------------+----------+ + +----------------------------------+
| | CVE-2018-16842 | MEDIUM | | | curl: Heap-based buffer |
| | | | | | over-read in the curl tool |
| | | | | | warning formatting |
+ +------------------+ + +---------------+----------------------------------+
| | CVE-2018-16890 | | | 7.61.1-r2 | curl: NTLM type-2 heap |
| | | | | | out-of-bounds buffer read |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3823 | | | | curl: SMTP end-of-response |
| | | | | | out-of-bounds read |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| git | CVE-2018-17456 | HIGH | 2.15.2-r0 | 2.15.3-r0 | git: arbitrary code execution |
| | | | | | via .gitmodules |
+ +------------------+ + + +----------------------------------+
| | CVE-2018-19486 | | | | git: Improper handling of |
| | | | | | PATH allows for commands to be |
| | | | | | executed from... |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| libssh2 | CVE-2019-3855 | CRITICAL | 1.8.0-r2 | 1.8.1-r0 | libssh2: Integer overflow in |
| | | | | | transport read resulting in |
| | | | | | out of bounds write... |
+ +------------------+----------+ + +----------------------------------+
| | CVE-2019-3859 | MEDIUM | | | libssh2: Unchecked use of |
| | | | | | _libssh2_packet_require and |
| | | | | | _libssh2_packet_requirev |
| | | | | | resulting in out-of-bounds |
| | | | | | read |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3858 | | | | libssh2: Zero-byte allocation |
| | | | | | with a specially crafted SFTP |
| | | | | | packed leading to an... |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3863 | | | | libssh2: Integer overflow |
| | | | | | in user authenticate |
| | | | | | keyboard interactive allows |
| | | | | | out-of-bounds writes |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3862 | | | | libssh2: Out-of-bounds memory |
| | | | | | comparison with specially |
| | | | | | crafted message channel |
| | | | | | request |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3860 | | | | libssh2: Out-of-bounds reads |
| | | | | | with specially crafted SFTP |
| | | | | | packets |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3857 | | | | libssh2: Integer overflow in |
| | | | | | SSH packet processing channel |
| | | | | | resulting in out of... |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3861 | | | | libssh2: Out-of-bounds reads |
| | | | | | with specially crafted SSH |
| | | | | | packets |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-3856 | | | | libssh2: Integer overflow in |
| | | | | | keyboard interactive handling |
| | | | | | resulting in out of bounds... |
+---------+------------------+ +-------------------+---------------+----------------------------------+
| libxml2 | CVE-2018-14567 | | 2.9.7-r0 | 2.9.8-r1 | libxml2: Infinite loop when |
| | | | | | --with-lzma is used allows for |
| | | | | | denial of service... |
+ +------------------+ + + +----------------------------------+
| | CVE-2018-14404 | | | | libxml2: NULL pointer |
| | | | | | dereference in |
| | | | | | xpath.c:xmlXPathCompOpEval() |
| | | | | | can allow attackers to cause |
| | | | | | a... |
+ +------------------+----------+ + +----------------------------------+
| | CVE-2018-9251 | LOW | | | libxml2: infinite loop in |
| | | | | | xz_decomp function in xzlib.c |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| openssh | CVE-2019-6109 | MEDIUM | 7.5_p1-r9 | 7.5_p1-r10 | openssh: Missing character |
| | | | | | encoding in progress display |
| | | | | | allows for spoofing of scp... |
+ +------------------+ + + +----------------------------------+
| | CVE-2019-6111 | | | | openssh: Improper validation |
| | | | | | of object names allows |
| | | | | | malicious server to overwrite |
| | | | | | files... |
+ +------------------+----------+ + +----------------------------------+
| | CVE-2018-20685 | LOW | | | openssh: scp client improper |
| | | | | | directory name validation |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| sqlite | CVE-2018-20346 | MEDIUM | 3.21.0-r1 | 3.25.3-r0 | sqlite: Multiple flaws in |
| | | | | | sqlite which can be triggered |
| | | | | | via corrupted internal... |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
| tar | CVE-2018-20482 | LOW | 1.29-r1 | 1.31-r0 | tar: Infinite read loop in |
| | | | | | sparse_dump_region function in |
| | | | | | sparse.c |
+---------+------------------+----------+-------------------+---------------+----------------------------------+
ruby-app/Gemfile.lock
=====================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
+----------------------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+----------------------+------------------+----------+-------------------+---------------+--------------------------------+
| rails-html-sanitizer | CVE-2018-3741 | MEDIUM | 1.0.3 | >= 1.0.4 | rubygem-rails-html-sanitizer: |
| | | | | | non-whitelisted attributes |
| | | | | | are present in sanitized |
| | | | | | output when input with |
| | | | | | specially-crafted... |
+----------------------+------------------+----------+-------------------+---------------+--------------------------------+
rust-app/Cargo.lock
===================
Total: 3 (UNKNOWN: 3, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
+---------+-------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+-------------------+----------+-------------------+---------------+--------------------------------+
| ammonia | RUSTSEC-2019-0001 | UNKNOWN | 1.9.0 | >= 2.1.0 | Uncontrolled recursion leads |
| | | | | | to abort in HTML serialization |
+---------+-------------------+ +-------------------+---------------+--------------------------------+
| openssl | RUSTSEC-2016-0001 | | 0.8.3 | >= 0.9.0 | SSL/TLS MitM vulnerability due |
| | | | | | to insecure defaults |
+ +-------------------+ + +---------------+--------------------------------+
| | RUSTSEC-2018-0010 | | | >= 0.10.9 | Use after free in CMS Signing |
+---------+-------------------+----------+-------------------+---------------+--------------------------------+
php-app/composer.lock
=====================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
+-------------------+------------------+----------+-------------------+---------------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+-------------------+------------------+----------+-------------------+---------------------+--------------------------------+
| guzzlehttp/guzzle | CVE-2016-5385 | MEDIUM | 6.2.0 | 6.2.1, 4.2.4, 5.3.1 | PHP: sets environmental |
| | | | | | variable based on user |
| | | | | | supplied Proxy request header |
+-------------------+------------------+----------+-------------------+---------------------+--------------------------------+
node-app/package-lock.json
==========================
Total: 4 (UNKNOWN: 0, LOW: 0, MEDIUM: 3, HIGH: 1, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| jquery | CVE-2019-5428 | MEDIUM | 3.3.9 | >=3.4.0 | Modification of |
| | | | | | Assumed-Immutable Data (MAID) |
+ +------------------+ + + +--------------------------------+
| | CVE-2019-11358 | | | | js-jquery: prototype pollution |
| | | | | | in object's prototype leading |
| | | | | | to denial of service or... |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| lodash | CVE-2018-16487 | HIGH | 4.17.4 | >=4.17.11 | lodash: Prototype pollution in |
| | | | | | utilities function |
+ +------------------+----------+ +---------------+ +
| | CVE-2018-3721 | MEDIUM | | >=4.17.5 | |
| | | | | | |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
python-app/Pipfile.lock
=======================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+------------------------------------+
| django | CVE-2019-6975 | MEDIUM | 2.0.9 | 2.0.11 | python-django: |
| | | | | | memory exhaustion in |
| | | | | | django.utils.numberformat.format() |
+---------+------------------+----------+-------------------+---------------+------------------------------------+
```
</details>
### Scan an image file
```
@@ -203,50 +461,45 @@ $ trivy --input ruby-2.3.0.tar
<summary>Result</summary>
```
2019-05-16T01:40:44.254+0900 INFO Updating vulnerability database...
2019-05-16T01:40:46.035+0900 INFO Detecting Debian vulnerabilities...
2019-05-16T12:45:57.332+0900 INFO Updating vulnerability database...
2019-05-16T12:45:59.119+0900 INFO Detecting Debian vulnerabilities...
ruby-2.3.0.tar (debian 8.4)
===========================
Total: 8136 (UNKNOWN: 5, LOW: 326, MEDIUM: 6020, HIGH: 1680, CRITICAL: 105)
Total: 7447 (UNKNOWN: 5, LOW: 326, MEDIUM: 5695, HIGH: 1316, CRITICAL: 105)
+-----------------------------+------------------+----------+---------------------------+----------------------------------+-------------------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+-----------------------------+------------------+----------+---------------------------+----------------------------------+-------------------------------------------------+
| bash | CVE-2016-7543 | HIGH | 4.3-11 | 4.3-11+deb8u1 | bash: Specially crafted |
| | | | | | SHELLOPTS+PS4 variables allows |
| | | | | | command substitution |
+ +------------------+ + +----------------------------------+-------------------------------------------------+
| | CVE-2019-9924 | | | 4.3-11+deb8u2 | bash: BASH_CMD is writable in |
| | | | | | restricted bash shells |
+-----------------------------+------------------+ +---------------------------+----------------------------------+-------------------------------------------------+
| binutils | CVE-2017-13716 | | 2.25-5 | | binutils: Memory leak with the |
| | | | | | C++ symbol demangler routine |
| | | | | | in libiberty |
+ +------------------+ + +----------------------------------+-------------------------------------------------+
| | CVE-2017-14930 | | | | binutils: Memory leak in |
| | | | | | decode_line_info |
+ +------------------+ + +----------------------------------+-------------------------------------------------+
| | CVE-2017-8421 | | | | binutils: Memory exhaustion in |
| | | | | | objdump via a crafted PE file |
+ +------------------+ + +----------------------------------+-------------------------------------------------+
| | CVE-2017-7614 | | | | binutils: NULL |
| | | | | | pointer dereference in |
| | | | | | bfd_elf_final_link function |
+ +------------------+ + +----------------------------------+-------------------------------------------------+
| | CVE-2018-12699 | | | | binutils: heap-based buffer |
| | | | | | overflow in finish_stab in |
| | | | | | stabs.c |
+ +------------------+ + +----------------------------------+-------------------------------------------------+
| | CVE-2014-9939 | | | | binutils: buffer overflow in |
| | | | | | ihex.c |
+-----------------------------+------------------+ +---------------------------+----------------------------------+-------------------------------------------------+
+------------------------------+---------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+------------------------------+---------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
| apt | CVE-2019-3462 | CRITICAL | 1.0.9.8.3 | 1.0.9.8.5 | Incorrect sanitation of the |
| | | | | | 302 redirect field in HTTP |
| | | | | | transport method of... |
+ +---------------------+----------+ +----------------------------------+-----------------------------------------------------+
| | CVE-2016-1252 | MEDIUM | | 1.0.9.8.4 | The apt package in Debian |
| | | | | | jessie before 1.0.9.8.4, in |
| | | | | | Debian unstable before... |
+ +---------------------+----------+ +----------------------------------+-----------------------------------------------------+
| | CVE-2011-3374 | LOW | | | |
+------------------------------+---------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
| bash | CVE-2016-7543 | HIGH | 4.3-11 | 4.3-11+deb8u1 | bash: Specially crafted |
| | | | | | SHELLOPTS+PS4 variables allows |
| | | | | | command substitution |
+ +---------------------+ + +----------------------------------+-----------------------------------------------------+
| | CVE-2019-9924 | | | 4.3-11+deb8u2 | bash: BASH_CMD is writable in |
| | | | | | restricted bash shells |
+ +---------------------+----------+ +----------------------------------+-----------------------------------------------------+
| | CVE-2016-0634 | MEDIUM | | 4.3-11+deb8u1 | bash: Arbitrary code execution |
| | | | | | via malicious hostname |
+ +---------------------+----------+ +----------------------------------+-----------------------------------------------------+
| | CVE-2016-9401 | LOW | | 4.3-11+deb8u2 | bash: popd controlled free |
+ +---------------------+ + +----------------------------------+-----------------------------------------------------+
| | TEMP-0841856-B18BAF | | | | |
+------------------------------+---------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------
...
```
</details>
### Save the results as JSON
```
@@ -263,6 +516,115 @@ $ trivy -f json -o results.json golang:1.12-alpine
</details>
<details>
<summary>JSON</summary>
```
[
{
"Target": "php-app/composer.lock",
"Vulnerabilities": null
},
{
"Target": "node-app/package-lock.json",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2018-16487",
"PkgName": "lodash",
"InstalledVersion": "4.17.4",
"FixedVersion": "\u003e=4.17.11",
"Title": "lodash: Prototype pollution in utilities function",
"Description": "A prototype pollution vulnerability was found in lodash \u003c4.17.11 where the functions merge, mergeWith, and defaultsDeep can be tricked into adding or modifying properties of Object.prototype.",
"Severity": "HIGH",
"References": [
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16487",
]
}
]
},
{
"Target": "trivy-ci-test (alpine 3.7.1)",
"Vulnerabilities": [
{
"VulnerabilityID": "CVE-2018-16840",
"PkgName": "curl",
"InstalledVersion": "7.61.0-r0",
"FixedVersion": "7.61.1-r1",
"Title": "curl: Use-after-free when closing \"easy\" handle in Curl_close()",
"Description": "A heap use-after-free flaw was found in curl versions from 7.59.0 through 7.61.1 in the code related to closing an easy handle. ",
"Severity": "HIGH",
"References": [
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-16840",
]
},
{
"VulnerabilityID": "CVE-2019-3822",
"PkgName": "curl",
"InstalledVersion": "7.61.0-r0",
"FixedVersion": "7.61.1-r2",
"Title": "curl: NTLMv2 type-3 header stack buffer overflow",
"Description": "libcurl versions from 7.36.0 to before 7.64.0 are vulnerable to a stack-based buffer overflow. ",
"Severity": "HIGH",
"References": [
"https://curl.haxx.se/docs/CVE-2019-3822.html",
"https://lists.apache.org/thread.html/8338a0f605bdbb3a6098bb76f666a95fc2b2f53f37fa1ecc89f1146f@%3Cdevnull.infra.apache.org%3E"
]
},
{
"VulnerabilityID": "CVE-2018-16839",
"PkgName": "curl",
"InstalledVersion": "7.61.0-r0",
"FixedVersion": "7.61.1-r1",
"Title": "curl: Integer overflow leading to heap-based buffer overflow in Curl_sasl_create_plain_message()",
"Description": "Curl versions 7.33.0 through 7.61.1 are vulnerable to a buffer overrun in the SASL authentication code that may lead to denial of service.",
"Severity": "HIGH",
"References": [
"https://github.com/curl/curl/commit/f3a24d7916b9173c69a3e0ee790102993833d6c5",
]
},
{
"VulnerabilityID": "CVE-2018-19486",
"PkgName": "git",
"InstalledVersion": "2.15.2-r0",
"FixedVersion": "2.15.3-r0",
"Title": "git: Improper handling of PATH allows for commands to be executed from the current directory",
"Description": "Git before 2.19.2 on Linux and UNIX executes commands from the current working directory (as if '.' were at the end of $PATH) in certain cases involving the run_command() API and run-command.c, because there was a dangerous change from execvp to execv during 2017.",
"Severity": "HIGH",
"References": [
"https://usn.ubuntu.com/3829-1/",
]
},
{
"VulnerabilityID": "CVE-2018-17456",
"PkgName": "git",
"InstalledVersion": "2.15.2-r0",
"FixedVersion": "2.15.3-r0",
"Title": "git: arbitrary code execution via .gitmodules",
"Description": "Git before 2.14.5, 2.15.x before 2.15.3, 2.16.x before 2.16.5, 2.17.x before 2.17.2, 2.18.x before 2.18.1, and 2.19.x before 2.19.1 allows remote code execution during processing of a recursive \"git clone\" of a superproject if a .gitmodules file has a URL field beginning with a '-' character.",
"Severity": "HIGH",
"References": [
"http://www.securitytracker.com/id/1041811",
]
}
]
},
{
"Target": "python-app/Pipfile.lock",
"Vulnerabilities": null
},
{
"Target": "ruby-app/Gemfile.lock",
"Vulnerabilities": null
},
{
"Target": "rust-app/Cargo.lock",
"Vulnerabilities": null
}
]
```
</details>
### Filter the vulnerabilities by severities
```
@@ -328,35 +690,115 @@ Total: 1785 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1680, CRITICAL: 105)
### Skip an update of vulnerability DB
`Trivy` updates vulnerability database every time it is run. This is usually fast as it is a difference update. But if you want to skip even that, use the `--skip-update` option.
`Trivy` always updates vulnerability database when it starts operating. This is usually fast as it is a difference update. But if you want to skip even that, use the `--skip-update` option.
```
$ trivy --skip-update alpine:3.9
$ trivy --skip-update python:3.4-alpine3.9
```
<details>
<summary>Result</summary>
```
2019-05-16T12:48:08.703+0900 INFO Detecting Alpine vulnerabilities...
python:3.4-alpine3.9 (alpine 3.9.2)
===================================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| openssl | CVE-2019-1543 | MEDIUM | 1.1.1a-r1 | 1.1.1b-r1 | openssl: ChaCha20-Poly1305 |
| | | | | | with long nonces |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
```
</details>
### Ignore unfixed vulnerabilities
By default, `Trivy` also detects unpatched/unfixed vulnerabilities. This means you can't fix these vulnerabilities even if you update all packages.
If you would like to ignore them, use the `--ignore-unfixed` option.
```
$ trivy --exit-code 1 httpd:2.4.39
$ trivy --ignore-unfixed ruby:2.3.0
```
<details>
<summary>Result</summary>
```
2019-05-16T12:49:52.656+0900 INFO Updating vulnerability database...
2019-05-16T12:50:14.786+0900 INFO Detecting Debian vulnerabilities...
ruby:2.3.0 (debian 8.4)
=======================
Total: 4730 (UNKNOWN: 1, LOW: 145, MEDIUM: 3487, HIGH: 1014, CRITICAL: 83)
+------------------------------+------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+------------------------------+------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
| apt | CVE-2019-3462 | CRITICAL | 1.0.9.8.3 | 1.0.9.8.5 | Incorrect sanitation of the |
| | | | | | 302 redirect field in HTTP |
| | | | | | transport method of... |
+ +------------------+----------+ +----------------------------------+-----------------------------------------------------+
| | CVE-2016-1252 | MEDIUM | | 1.0.9.8.4 | The apt package in Debian |
| | | | | | jessie before 1.0.9.8.4, in |
| | | | | | Debian unstable before... |
+------------------------------+------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
| bash | CVE-2019-9924 | HIGH | 4.3-11 | 4.3-11+deb8u2 | bash: BASH_CMD is writable in |
| | | | | | restricted bash shells |
+ +------------------+ + +----------------------------------+-----------------------------------------------------+
| | CVE-2016-7543 | | | 4.3-11+deb8u1 | bash: Specially crafted |
| | | | | | SHELLOPTS+PS4 variables allows |
| | | | | | command substitution |
+ +------------------+----------+ + +-----------------------------------------------------+
| | CVE-2016-0634 | MEDIUM | | | bash: Arbitrary code execution |
| | | | | | via malicious hostname |
+ +------------------+----------+ +----------------------------------+-----------------------------------------------------+
| | CVE-2016-9401 | LOW | | 4.3-11+deb8u2 | bash: popd controlled free |
+------------------------------+------------------+----------+----------------------------+----------------------------------+-----------------------------------------------------+
...
```
</details>
### Specify exit code
By default, `Trivy` exits with code 0 even when vulnerabilities are detected.
Use the `--exit-code` option if you want to exit with a non-zero exit code.
```
$ trivy --exit-code 1 httpd:2.4.39
$ trivy --exit-code 1 python:3.4-alpine3.9
```
<details>
<summary>Result</summary>
```
2019-05-16T12:51:43.500+0900 INFO Updating vulnerability database...
2019-05-16T12:52:00.387+0900 INFO Detecting Alpine vulnerabilities...
python:3.4-alpine3.9 (alpine 3.9.2)
===================================
Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
| openssl | CVE-2019-1543 | MEDIUM | 1.1.1a-r1 | 1.1.1b-r1 | openssl: ChaCha20-Poly1305 |
| | | | | | with long nonces |
+---------+------------------+----------+-------------------+---------------+--------------------------------+
```
</details>
This option is useful for CI/CD. In the following example, the test will fail only when a critical vulnerability is found.
```
$ trivy --exit-code 0 --severity MEDIUM,HIGH httpd:2.4.39
$ trivy --exit-code 1 --severity CRITICAL httpd:2.4.39
$ trivy --exit-code 0 --severity MEDIUM,HIGH ruby:2.3.0
$ trivy --exit-code 1 --severity CRITICAL ruby:2.3.0
```
### Ignore the specified vulnerabilities
@@ -369,19 +811,58 @@ $ cat .trivyignore
CVE-2018-14618
# No impact in our settings
CVE-2019-3855
CVE-2019-1543
$ trivy composer:1.7.2
$ trivy python:3.4-alpine3.9
```
<details>
<summary>Result</summary>
```
2019-05-16T12:53:10.076+0900 INFO Updating vulnerability database...
2019-05-16T12:53:28.134+0900 INFO Detecting Alpine vulnerabilities...
python:3.4-alpine3.9 (alpine 3.9.2)
===================================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
```
</details>
### Clear image caches
The `--clear-cache` option removes image caches. This option is useful if the image which has the same tag is updated (such as when using `latest` tag).
```
$ trivy --clear-cache redis:5.0.4
$ trivy --clear-cache python:3.7
```
<details>
<summary>Result</summary>
```
2019-05-16T12:55:24.749+0900 INFO Removing image caches...
2019-05-16T12:55:24.769+0900 INFO Updating vulnerability database...
2019-05-16T12:56:14.055+0900 INFO Detecting Debian vulnerabilities...
python:3.7 (debian 9.9)
=======================
Total: 3076 (UNKNOWN: 0, LOW: 127, MEDIUM: 2358, HIGH: 578, CRITICAL: 13)
+------------------------------+---------------------+----------+--------------------------+------------------+-------------------------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+------------------------------+---------------------+----------+--------------------------+------------------+-------------------------------------------------------+
| apt | CVE-2011-3374 | LOW | 1.4.9 | | |
+------------------------------+---------------------+ +--------------------------+------------------+-------------------------------------------------------+
| bash | TEMP-0841856-B18BAF | | 4.4-5 | | |
+------------------------------+---------------------+----------+--------------------------+------------------+-------------------------------------------------------+
...
```
</details>
### Reset
The `--reset` option removes all caches and database. After this, it takes a long time as the vulnerability database needs to be rebuilt locally.
@@ -390,11 +871,20 @@ The `--reset` option removes all caches and database. After this, it takes a lon
$ trivy --reset
```
<details>
<summary>Result</summary>
```
2019-05-16T13:05:31.935+0900 INFO Resetting...
```
</details>
# Continuous Integration (CI)
Scan your image built in Travis CI/CircleCI. The test will fail if a vulnerability is found. When you don't want to fail the test, specify `--exit-code 0` .
**Note**: The first time take a while (faster by cache after the second time)
**Note**: It will take a while for the first time (faster by cache after the second time)
## Travis CI
@@ -409,11 +899,12 @@ env:
before_install:
- docker build -t trivy-ci-test:${COMMIT} .
- wget https://github.com/knqyf263/trivy/releases/download/v0.0.4/trivy_0.0.4_Linux-64bit.tar.gz
- tar zxvf trivy_0.0.4_Linux-64bit.tar.gz
- export VERSION=$(curl --silent "https://api.github.com/repos/knqyf263/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
- wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
- tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
script:
- ./trivy --exit-code 0 --severity HIGH --quiet trivy-ci-test:${COMMIT}
- ./trivy --exit-code 1 --severity CRITICAL --quiet trivy-ci-test:${COMMIT}
- ./trivy --exit-code 0 --severity HIGH --quiet --auto-refresh trivy-ci-test:${COMMIT}
- ./trivy --exit-code 1 --severity CRITICAL --quiet --auto-refresh trivy-ci-test:${COMMIT}
cache:
directories:
- $HOME/.cache/trivy
@@ -425,6 +916,7 @@ Repository: https://github.com/knqyf263/trivy-ci-test
## CircleCI
```
$ cat .circleci/config.yml
jobs:
build:
docker:
@@ -440,12 +932,19 @@ jobs:
- run:
name: Install trivy
command: |
wget https://github.com/knqyf263/trivy/releases/download/v0.0.4/trivy_0.0.4_Linux-64bit.tar.gz
tar zxvf trivy_0.0.4_Linux-64bit.tar.gz
apk add --update curl
VERSION=$(
curl --silent "https://api.github.com/repos/knqyf263/trivy/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/'
)
wget https://github.com/knqyf263/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
mv trivy /usr/local/bin
- run:
name: Scan the local image with trivy
command: trivy --exit-code 0 --quiet trivy-ci-test:${CIRCLE_SHA1}
command: trivy --exit-code 0 --quiet --auto-refresh trivy-ci-test:${CIRCLE_SHA1}
- save_cache:
key: vulnerability-db
paths:
@@ -453,7 +952,7 @@ jobs:
workflows:
version: 2
release:
jobs:
jobs:
- build
```
@@ -464,14 +963,16 @@ Repository: https://github.com/knqyf263/trivy-ci-test
## OS Packages
| OS | Supported Versions | Target Packages | Detection of unfixed vulnerabilities |
| ---------------------------- | ---------------------------------------- | -------------------------------------- | --- |
| Alpine Linux | 2.2 - 2.7, 3.0 - 3.10 | Installed by apk | NO |
| Red Hat Universal Base Image | 7, 8 | Installed by yum/rpm | YES |
| Red Hat Enterprise Linux | 6, 7, 8 | Installed by yum/rpm | YES |
| CentOS | 6, 7 | Installed by yum/rpm | YES |
| Debian GNU/Linux | wheezy, jessie, stretch, buster | Installed by apt/apt-get/dpkg | YES |
| Ubuntu | 12.04, 14.04, 16.04, 18.04, 18.10, 19.04 | Installed by apt/apt-get/dpkg | YES |
The unfixed/unfixable vulnerabilities mean that the patch has not yet been provided on their distribution.
| OS | Supported Versions | Target Packages | Detection of unfixed vulnerabilities |
| ---------------------------- | ---------------------------------------- | ----------------------------- | :----------------------------------: |
| Alpine Linux | 2.2 - 2.7, 3.0 - 3.10 | Installed by apk | NO |
| Red Hat Universal Base Image | 7, 8 | Installed by yum/rpm | YES |
| Red Hat Enterprise Linux | 6, 7, 8 | Installed by yum/rpm | YES |
| CentOS | 6, 7 | Installed by yum/rpm | YES |
| Debian GNU/Linux | wheezy, jessie, stretch, buster | Installed by apt/apt-get/dpkg | YES |
| Ubuntu | 12.04, 14.04, 16.04, 18.04, 18.10, 19.04 | Installed by apt/apt-get/dpkg | YES |
## Application Dependencies
@@ -496,7 +997,7 @@ NAME:
USAGE:
main [options] image_name
VERSION:
0.0.12
0.0.15
OPTIONS:
--format value, -f value format (table, json) (default: "table")
--input value, -i value input file path instead of image name
@@ -509,6 +1010,7 @@ OPTIONS:
--quiet, -q suppress progress bar
--ignore-unfixed display only fixed vulnerabilities
--refresh refresh DB (usually used after version update of trivy)
--auto-refresh refresh DB automatically when updating version of trivy
--debug, -d debug mode
--help, -h show help
--version, -v print the version
@@ -518,15 +1020,15 @@ OPTIONS:
## Overview
| Scanner | OS<br>Packages | Application<br>Dependencie | Easy to use | Accuracy | Compatible<br>with CI |
|----------------|-------------|:-----------------------:|-------------|----------|--------------------|
| Trivy | | | | | |
| Clair | | × | | | |
| Anchore Engine | | | | | |
| Quay | | × | | | × |
| MicroScanner | | × | | | |
| Docker Hub | | × | | × | × |
| GCR | | × | | | × |
| Scanner | OS<br>Packages | Application<br>Dependencies | Easy to use | Accuracy | Suitable<br>for CI |
| -------------- | :------------: | :-------------------------: | :---------: | :------: | :-------------------: |
| Trivy | | | | | |
| Clair | | × | | | |
| Anchore Engine | | | | | |
| Quay | | × | | | × |
| MicroScanner | | × | | | |
| Docker Hub | | × | | × | × |
| GCR | | × | | | × |
## Accuracy
@@ -549,7 +1051,7 @@ The results of [composer:1.7.2](https://hub.docker.com/_/composer?tab=tags) usin
<img src="imgs/alpine.png" width="500">
`Trivy` has high accuracy and high precision, while GCR did not detect any vulnerability. Althogh Docker Hub has many True Positive, it also has many False Positive.
`Trivy` has high accuracy and high precision, while GCR did not detect any vulnerability. Although Docker Hub has many True Positive, it also has many False Positive.
### RHEL/CentOS
@@ -561,7 +1063,7 @@ The following chart includes only fixable vulnerabilities.
Most scanners only detect patched/fixable vulnerabilities on RHEL/CentOS, but `Trivy` also detects unpatched/unfixable vulnerabilities.
The below is the graph including unfixable vulnerabilities.
This graph includes unfixable vulnerabilities as well.
<img src="imgs/centos_include_unfixable.png" width="500">
@@ -575,8 +1077,8 @@ In the case of other OS, the result is similar to other container scanners.
However, the purpose of this database is to make it possible to know what packages has backported fixes.
As README says, it is not a complete database of all security issues in Alpine.
`Trivy` collects vulnerability information in Alpine Linux from [Alpine LInux Redmine](https://bugs.alpinelinux.org/projects/alpine/issues).
Then, those vulnerabilities will be saved on [vuln-list](https://github.com/knqyf263/vuln-list/tree/master/alpine)
`Trivy` collects vulnerability information in Alpine Linux from [Alpine Linux Redmine](https://bugs.alpinelinux.org/projects/alpine/issues).
Then, those vulnerabilities will be saved on [vuln-list](https://github.com/knqyf263/vuln-list/tree/master/alpine).
`alpine-secdb` has 6959 vulnerabilities (as of 2019/05/12).
`vuln-list` has 11101 vulnerabilities related with Alpine Linux (as of 2019/05/12).
@@ -584,7 +1086,7 @@ There is a difference in detection accuracy because the number of vulnerabilitie
In addition, `Trivy` analyzes the middle layer as well and find out which version of the library was used for static linking.
`Clair` can not handle the following cases because it analyzes the image after applying the all layers.
`Clair` can not handle the following cases because it analyzes the image after applying all layers.
```
RUN apk add --no-cache sqlite-dev \
@@ -594,6 +1096,8 @@ RUN apk add --no-cache sqlite-dev \
&& apk del sqlite-dev
```
And as many people know, it is difficult to select a `Clair` client because many clients are deprecated.
Finally, `Trivy` can also detect vulnerabilities in application dependent libraries such as Bundler, Composer, Pipenv, etc.
## vs Anchore Engine
@@ -606,9 +1110,9 @@ Also, `Anchore Engine` needs some steps to start scanning.
## vs Quay, Docker Hub, GCR
As `Quay` seems to use `Clair` internally, it has the same accuracy with `Clair`. `Docker Hub` can scan only official images. `GCR` hardly detects vulnerability on Alpine Linux. Also, it is locked to a specific registry.
As `Quay` seems to use `Clair` internally, it has the same accuracy than `Clair`. `Docker Hub` can scan only official images. `GCR` hardly detects vulnerabilities on Alpine Linux. Also, it is locked to a specific registry.
`Trivy` does not depend on the registry. In addition, it is easy to be integrated with CI/CD services.
`Trivy` can be used regardless of the registry. In addition, it is easy to be integrated with CI/CD services.
# Q&A
@@ -666,6 +1170,11 @@ Try again with `--reset` option
$ trivy --reset
```
# Related Projects
- [Remic](https://github.com/knqyf263/remic)
- Vulnerability Scanner for Detecting Publicly Disclosed Vulnerabilities in Application Dependencies
# Contribute
1. fork a repository: github.com/knqyf263/trivy to github.com/you/repo
@@ -683,6 +1192,7 @@ $ trivy --reset
- Special thanks to [Tomoya Amachi](https://github.com/tomoyamachi)
- Special thanks to [Masahiro Fujimura](https://github.com/masahiro331)
- Special thanks to [Naoki Harima](https://github.com/XapiMa)
# License

View File

@@ -89,20 +89,26 @@ OPTIONS:
Name: "refresh",
Usage: "refresh DB (usually used after version update of trivy)",
},
cli.BoolFlag{
Name: "auto-refresh",
Usage: "refresh DB automatically when updating version of trivy",
},
cli.BoolFlag{
Name: "debug, d",
Usage: "debug mode",
},
cli.StringFlag{
Name: "cache-dir",
Usage: "cache directory",
},
}
app.Action = func(c *cli.Context) error {
return pkg.Run(c)
}
app.Action = pkg.Run
err := app.Run(os.Args)
if err != nil {
if log.Logger != nil {
log.Logger.Fatal(err)
log.Fatal(err)
}
l.Fatal(err)
}

4
go.mod
View File

@@ -11,8 +11,8 @@ require (
github.com/genuinetools/reg v0.16.0
github.com/gliderlabs/ssh v0.1.3 // indirect
github.com/golang/protobuf v1.3.1 // indirect
github.com/knqyf263/fanal v0.0.0-20190516002914-a1530cdb9a80
github.com/knqyf263/go-deb-version v0.0.0-20170509080151-9865fe14d09b
github.com/knqyf263/fanal v0.0.0-20190517090627-af48380166ef
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-dep-parser v0.0.0-20190515172517-b8305876c9c2
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/go-version v1.1.1

8
go.sum
View File

@@ -114,10 +114,10 @@ github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp
github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knqyf263/berkeleydb v0.0.0-20190501065933-fafe01fb9662/go.mod h1:bu1CcN4tUtoRcI/B/RFHhxMNKFHVq/c3SV+UTyduoXg=
github.com/knqyf263/fanal v0.0.0-20190516002914-a1530cdb9a80 h1:6cXQOaOGU33P+22DKh6n7Pp+Tb5DLPwvqlJ7De34ZMg=
github.com/knqyf263/fanal v0.0.0-20190516002914-a1530cdb9a80/go.mod h1:NQxdeR5taRqHUw9B2zkPCh/klHFaFb13j8QcQ6yxg60=
github.com/knqyf263/go-deb-version v0.0.0-20170509080151-9865fe14d09b h1:DiDMmSwuY27PJxA2Gs0+uI/bQ/ehKARaGXRdlp+wFis=
github.com/knqyf263/go-deb-version v0.0.0-20170509080151-9865fe14d09b/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
github.com/knqyf263/fanal v0.0.0-20190517090627-af48380166ef h1:mxKy5exy/vKIhV86Ar7E1AzNS/NCjfyrcRKcoblgZd8=
github.com/knqyf263/fanal v0.0.0-20190517090627-af48380166ef/go.mod h1:bycEQTZsPG1IOBXWwTNxruhtNN0KYDgux0CMgu9UGoQ=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
github.com/knqyf263/go-dep-parser v0.0.0-20190515172517-b8305876c9c2 h1:bQGj8WH6X4czC2FlkgUKKFq2xPnJovzf61T4Yl9sVZs=
github.com/knqyf263/go-dep-parser v0.0.0-20190515172517-b8305876c9c2/go.mod h1:gSiqSkOFPstUZu/qZ4wnNJS69PtQQnPl397vxKHJ5mQ=
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936 h1:HDjRqotkViMNcGMGicb7cgxklx8OwnjtCBmyWEqrRvM=

Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
imgs/usage1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 315 KiB

BIN
imgs/usage2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 KiB

View File

@@ -15,11 +15,11 @@ import (
)
var (
db *bolt.DB
dbDir = filepath.Join(utils.CacheDir(), "db")
db *bolt.DB
)
func Init() (err error) {
dbDir := filepath.Join(utils.CacheDir(), "db")
if err = os.MkdirAll(dbDir, 0700); err != nil {
return xerrors.Errorf("failed to mkdir: %w", err)
}
@@ -33,10 +33,26 @@ func Init() (err error) {
return nil
}
func Close() error {
if err := db.Close(); err != nil {
return xerrors.Errorf("failed to close DB: %w", err)
}
return nil
}
func Reset() error {
if err := Close(); err != nil {
return xerrors.Errorf("failed to reset DB: %w", err)
}
dbDir := filepath.Join(utils.CacheDir(), "db")
if err := os.RemoveAll(dbDir); err != nil {
return xerrors.Errorf("failed to reset DB: %w", err)
}
if err := Init(); err != nil {
return xerrors.Errorf("failed to reset DB: %w", err)
}
return nil
}
@@ -89,9 +105,7 @@ func Put(root *bolt.Bucket, nestedBucket, key string, value interface{}) error {
return nested.Put([]byte(key), v)
}
func BatchUpdate(fn func(tx *bolt.Tx) error) error {
err := db.Batch(func(tx *bolt.Tx) error {
return fn(tx)
})
err := db.Batch(fn)
if err != nil {
return xerrors.Errorf("error in batch update: %w", err)
}

View File

@@ -38,7 +38,7 @@ func CloneOrPull(url, repoPath string) (map[string]struct{}, error) {
}
log.Logger.Debug("remove an existed directory")
suffix := " The first time will take a while..."
suffix := " It will take a while for the first time..."
s := utils.NewSpinner(suffix)
s.Start()
defer s.Stop()

View File

@@ -6,9 +6,13 @@ import (
"golang.org/x/xerrors"
)
var Logger *zap.SugaredLogger
var (
Logger *zap.SugaredLogger
debugOption bool
)
func InitLogger(debug bool) (err error) {
debugOption = debug
Logger, err = newLogger(debug)
if err != nil {
return xerrors.Errorf("error in new logger: %w", err)
@@ -29,8 +33,8 @@ func newLogger(debug bool) (*zap.SugaredLogger, error) {
Level: level,
Encoding: "console",
Development: debug,
DisableStacktrace: !debug,
DisableCaller: !debug,
DisableStacktrace: true,
DisableCaller: true,
EncoderConfig: zapcore.EncoderConfig{
TimeKey: "Time",
LevelKey: "Level",
@@ -53,3 +57,10 @@ func newLogger(debug bool) (*zap.SugaredLogger, error) {
return logger.Sugar(), nil
}
func Fatal(err error) {
if debugOption {
Logger.Fatalf("%+v", err)
}
Logger.Fatal(err)
}

View File

@@ -17,8 +17,8 @@ import (
type Results []Result
type Result struct {
FileName string `json:"file"`
Vulnerabilities []vulnerability.DetectedVulnerability
FileName string `json:"Target"`
Vulnerabilities []vulnerability.DetectedVulnerability `json:"Vulnerabilities"`
}
type Writer interface {
@@ -84,11 +84,7 @@ type JsonWriter struct {
}
func (jw JsonWriter) Write(results Results) error {
out := map[string][]vulnerability.DetectedVulnerability{}
for _, result := range results {
out[result.FileName] = result.Vulnerabilities
}
output, err := json.MarshalIndent(out, "", " ")
output, err := json.MarshalIndent(results, "", " ")
if err != nil {
return xerrors.Errorf("failed to marshal json: %w", err)
}

View File

@@ -5,6 +5,7 @@ import (
"os"
"strings"
"github.com/genuinetools/reg/registry"
"github.com/knqyf263/fanal/cache"
"github.com/knqyf263/trivy/pkg/utils"
@@ -25,13 +26,21 @@ import (
func Run(c *cli.Context) (err error) {
cliVersion := c.App.Version
utils.Quiet = c.Bool("quiet")
debug := c.Bool("debug")
if err = log.InitLogger(debug); err != nil {
l.Fatal(err)
}
cacheDir := c.String("cache-dir")
if cacheDir != "" {
utils.SetCacheDir(cacheDir)
}
log.Logger.Debugf("cache dir: %s", utils.CacheDir())
if c.Bool("reset") {
reset := c.Bool("reset")
if reset {
log.Logger.Info("Resetting...")
if err = cache.Clear(); err != nil {
return xerrors.New("failed to remove image layer cache")
@@ -42,21 +51,65 @@ func Run(c *cli.Context) (err error) {
return nil
}
if c.Bool("clear-cache") {
clearCache := c.Bool("clear-cache")
if clearCache {
log.Logger.Info("Removing image caches...")
if err = cache.Clear(); err != nil {
return xerrors.New("failed to remove image layer cache")
}
}
refresh := c.Bool("refresh")
args := c.Args()
var noTarget bool
filePath := c.String("input")
if filePath == "" && len(args) == 0 {
log.Logger.Info(`trivy" requires at least 1 argument or --input option.`)
cli.ShowAppHelpAndExit(c, 1)
noTarget = true
if !reset && !clearCache && !refresh {
log.Logger.Info(`trivy" requires at least 1 argument or --input option.`)
cli.ShowAppHelpAndExit(c, 1)
}
}
utils.Quiet = c.Bool("quiet")
autoRefresh := c.Bool("auto-refresh")
skipUpdate := c.Bool("skip-update")
if (refresh || autoRefresh) && skipUpdate {
return xerrors.New("The --skip-update option can not be specified with the --refresh or --auto-refresh option")
}
if err = db.Init(); err != nil {
return xerrors.Errorf("error in vulnerability DB initialize: %w", err)
}
needRefresh := false
dbVersion := db.GetVersion()
if dbVersion != "" && dbVersion != cliVersion {
if !refresh && !autoRefresh {
return xerrors.New("Detected version update of trivy. Please try again with --refresh or --auto-refresh option")
}
needRefresh = true
}
if refresh || needRefresh {
log.Logger.Info("Refreshing DB...")
if err = db.Reset(); err != nil {
return xerrors.Errorf("error in refresh DB: %w", err)
}
}
if !skipUpdate {
if err = vulnsrc.Update(); err != nil {
return xerrors.Errorf("error in vulnerability DB update: %w", err)
}
}
if err = db.SetVersion(cliVersion); err != nil {
return xerrors.Errorf("unexpected error: %w", err)
}
// When specifying no image name and file name
if noTarget {
return nil
}
o := c.String("output")
output := os.Stdout
@@ -76,40 +129,29 @@ func Run(c *cli.Context) (err error) {
severities = append(severities, severity)
}
if c.Bool("refresh") {
log.Logger.Info("Resetting DB...")
if err = db.Reset(); err != nil {
return xerrors.Errorf("error in refresh DB: %w", err)
}
}
if err = db.Init(); err != nil {
return xerrors.Errorf("error in vulnerability DB initialize: %w", err)
}
dbVersion := db.GetVersion()
if dbVersion != "" && dbVersion != cliVersion {
log.Logger.Fatal("Detected version update of trivy. Please try again with --refresh option")
}
if !c.Bool("skip-update") {
if err = vulnsrc.Update(); err != nil {
return xerrors.Errorf("error in vulnerability DB update: %w", err)
}
}
ignoreUnfixed := c.Bool("ignore-unfixed")
var imageName string
if filePath == "" {
imageName = args[0]
}
// Check whether 'latest' tag is used
if imageName != "" {
image, err := registry.ParseImage(imageName)
if err != nil {
return xerrors.Errorf("invalid image: %w", err)
}
if image.Tag == "latest" && !clearCache {
log.Logger.Warn("You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed")
}
}
vulns, err := scanner.ScanImage(imageName, filePath)
if err != nil {
return xerrors.Errorf("error in image scan: %w", err)
}
var results report.Results
ignoreUnfixed := c.Bool("ignore-unfixed")
for path, vuln := range vulns {
results = append(results, report.Result{
FileName: path,
@@ -118,23 +160,19 @@ func Run(c *cli.Context) (err error) {
}
var writer report.Writer
switch c.String("format") {
switch format := c.String("format"); format {
case "table":
writer = &report.TableWriter{Output: output}
case "json":
writer = &report.JsonWriter{Output: output}
default:
xerrors.New("unknown format")
return xerrors.Errorf("unknown format: %v", format)
}
if err = writer.Write(results); err != nil {
return xerrors.Errorf("failed to write results: %w", err)
}
if err = db.SetVersion(cliVersion); err != nil {
return xerrors.Errorf("unexpected error: %w", err)
}
exitCode := c.Int("exit-code")
if exitCode != 0 {
for _, result := range results {

View File

@@ -41,7 +41,8 @@ func Scan(files extractor.FileMap) (string, string, []vulnerability.DetectedVuln
case fos.RedHat, fos.CentOS:
s = redhat.NewScanner()
default:
return "", "", nil, xerrors.New("unsupported os")
log.Logger.Warnf("unsupported os : %s", os.Family)
return "", "", nil, nil
}
pkgs, err := analyzer.GetPackages(files)
if err != nil {

View File

@@ -6,10 +6,8 @@ import (
"fmt"
"os"
"github.com/genuinetools/reg/registry"
"github.com/knqyf263/fanal/analyzer"
"github.com/knqyf263/fanal/extractor"
"github.com/knqyf263/trivy/pkg/log"
"github.com/knqyf263/trivy/pkg/scanner/library"
"github.com/knqyf263/trivy/pkg/scanner/ospkg"
"github.com/knqyf263/trivy/pkg/vulnsrc/vulnerability"
@@ -25,14 +23,6 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
var target string
var files extractor.FileMap
if imageName != "" {
image, err := registry.ParseImage(imageName)
if err != nil {
return nil, xerrors.Errorf("invalid image: %w", err)
}
if image.Tag == "latest" {
log.Logger.Warn("You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed")
}
target = imageName
files, err = analyzer.Analyze(ctx, imageName)
if err != nil {
@@ -58,8 +48,10 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
return nil, xerrors.Errorf("failed to scan image: %w", err)
}
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
results[imageDetail] = osVulns
if osFamily != "" {
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
results[imageDetail] = osVulns
}
libVulns, err := library.Scan(files)
if err != nil {

View File

@@ -12,15 +12,24 @@ import (
"golang.org/x/xerrors"
)
var cacheDir string
func CacheDir() string {
cacheDir, err := os.UserCacheDir()
if err != nil {
cacheDir = os.TempDir()
if cacheDir == "" {
var err error
cacheDir, err = os.UserCacheDir()
if err != nil {
cacheDir = os.TempDir()
}
}
dir := filepath.Join(cacheDir, "trivy")
return dir
}
func SetCacheDir(cd string) {
cacheDir = cd
}
func FileWalk(root string, targetFiles map[string]struct{}, walkFn func(r io.Reader, path string) error) error {
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {

View File

@@ -89,17 +89,16 @@ func getDetail(vulnID string) (Severity, string, string, []string) {
func getSeverity(details map[string]Vulnerability) Severity {
for _, source := range sources {
d, ok := details[source]
if !ok {
switch d, ok := details[source]; {
case !ok:
continue
}
if d.CvssScore > 0 {
case d.CvssScore > 0:
return scoreToSeverity(d.CvssScore)
} else if d.CvssScoreV3 > 0 {
case d.CvssScoreV3 > 0:
return scoreToSeverity(d.CvssScoreV3)
} else if d.Severity != 0 {
case d.Severity != 0:
return d.Severity
} else if d.SeverityV3 != 0 {
case d.SeverityV3 != 0:
return d.SeverityV3
}
}
@@ -151,14 +150,16 @@ func getReferences(details map[string]Vulnerability) []string {
}
func scoreToSeverity(score float64) Severity {
if score >= 9.0 {
switch {
case score >= 9.0:
return SeverityCritical
} else if score >= 7.0 {
case score >= 7.0:
return SeverityHigh
} else if score >= 4.0 {
case score >= 4.0:
return SeverityMedium
} else if score > 0.0 {
case score > 0.0:
return SeverityLow
default:
return SeverityUnknown
}
return SeverityUnknown
}

View File

@@ -47,7 +47,7 @@ func Update() (err error) {
return xerrors.Errorf("error in Alpine OVAL update: %w", err)
}
//Update RedHat
// Update RedHat
log.Logger.Info("Updating RedHat data...")
if err = redhat.Update(dir, updatedFiles); err != nil {
return xerrors.Errorf("error in RedHat update: %w", err)
@@ -65,7 +65,7 @@ func Update() (err error) {
return xerrors.Errorf("error in Debian OVAL update: %w", err)
}
//Update Ubuntu
// Update Ubuntu
log.Logger.Info("Updating Ubuntu data...")
if err = ubuntu.Update(dir, updatedFiles); err != nil {
return xerrors.Errorf("error in Ubuntu update: %w", err)