mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-17 01:48:10 -08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
073b315737 | ||
|
|
47c46fbe17 | ||
|
|
39572968bb | ||
|
|
4383764cae | ||
|
|
e0ef0563ce | ||
|
|
d9cf2c487d |
@@ -1 +1,2 @@
|
|||||||
|
.circleci
|
||||||
imgs
|
imgs
|
||||||
|
|||||||
123
README.md
123
README.md
@@ -136,7 +136,7 @@ $ sudo dpkg -i trivy_0.0.15_Linux-64bit.deb
|
|||||||
|
|
||||||
## Mac OS X / Homebrew
|
## Mac OS X / Homebrew
|
||||||
|
|
||||||
You can use homebrew on OS X.
|
You can use homebrew on Mac OS.
|
||||||
|
|
||||||
```
|
```
|
||||||
$ brew tap knqyf263/trivy
|
$ brew tap knqyf263/trivy
|
||||||
@@ -145,7 +145,7 @@ $ brew install knqyf263/trivy/trivy
|
|||||||
|
|
||||||
## Binary (Including Windows)
|
## 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.
|
You need to install `rpm` command for scanning RHEL/CentOS.
|
||||||
|
|
||||||
@@ -516,6 +516,115 @@ $ trivy -f json -o results.json golang:1.12-alpine
|
|||||||
|
|
||||||
</details>
|
</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
|
### Filter the vulnerabilities by severities
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -942,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">
|
<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
|
### RHEL/CentOS
|
||||||
|
|
||||||
@@ -968,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.
|
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.
|
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).
|
`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)
|
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).
|
`alpine-secdb` has 6959 vulnerabilities (as of 2019/05/12).
|
||||||
`vuln-list` has 11101 vulnerabilities related with Alpine Linux (as of 2019/05/12).
|
`vuln-list` has 11101 vulnerabilities related with Alpine Linux (as of 2019/05/12).
|
||||||
@@ -977,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.
|
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 \
|
RUN apk add --no-cache sqlite-dev \
|
||||||
@@ -1001,7 +1110,7 @@ Also, `Anchore Engine` needs some steps to start scanning.
|
|||||||
|
|
||||||
## vs Quay, Docker Hub, GCR
|
## 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` can be used regardless of 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.
|
||||||
|
|
||||||
|
|||||||
@@ -103,9 +103,7 @@ OPTIONS:
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Action = func(c *cli.Context) error {
|
app.Action = pkg.Run
|
||||||
return pkg.Run(c)
|
|
||||||
}
|
|
||||||
|
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -105,9 +105,7 @@ func Put(root *bolt.Bucket, nestedBucket, key string, value interface{}) error {
|
|||||||
return nested.Put([]byte(key), v)
|
return nested.Put([]byte(key), v)
|
||||||
}
|
}
|
||||||
func BatchUpdate(fn func(tx *bolt.Tx) error) error {
|
func BatchUpdate(fn func(tx *bolt.Tx) error) error {
|
||||||
err := db.Batch(func(tx *bolt.Tx) error {
|
err := db.Batch(fn)
|
||||||
return fn(tx)
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("error in batch update: %w", err)
|
return xerrors.Errorf("error in batch update: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ import (
|
|||||||
type Results []Result
|
type Results []Result
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
FileName string `json:"file"`
|
FileName string `json:"Target"`
|
||||||
Vulnerabilities []vulnerability.DetectedVulnerability
|
Vulnerabilities []vulnerability.DetectedVulnerability `json:"Vulnerabilities"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Writer interface {
|
type Writer interface {
|
||||||
@@ -84,11 +84,7 @@ type JsonWriter struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (jw JsonWriter) Write(results Results) error {
|
func (jw JsonWriter) Write(results Results) error {
|
||||||
out := map[string][]vulnerability.DetectedVulnerability{}
|
output, err := json.MarshalIndent(results, "", " ")
|
||||||
for _, result := range results {
|
|
||||||
out[result.FileName] = result.Vulnerabilities
|
|
||||||
}
|
|
||||||
output, err := json.MarshalIndent(out, "", " ")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("failed to marshal json: %w", err)
|
return xerrors.Errorf("failed to marshal json: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
12
pkg/run.go
12
pkg/run.go
@@ -102,6 +102,10 @@ func Run(c *cli.Context) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = db.SetVersion(cliVersion); err != nil {
|
||||||
|
return xerrors.Errorf("unexpected error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// When specifying no image name and file name
|
// When specifying no image name and file name
|
||||||
if noTarget {
|
if noTarget {
|
||||||
return nil
|
return nil
|
||||||
@@ -156,23 +160,19 @@ func Run(c *cli.Context) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var writer report.Writer
|
var writer report.Writer
|
||||||
switch c.String("format") {
|
switch format := c.String("format"); format {
|
||||||
case "table":
|
case "table":
|
||||||
writer = &report.TableWriter{Output: output}
|
writer = &report.TableWriter{Output: output}
|
||||||
case "json":
|
case "json":
|
||||||
writer = &report.JsonWriter{Output: output}
|
writer = &report.JsonWriter{Output: output}
|
||||||
default:
|
default:
|
||||||
xerrors.New("unknown format")
|
return xerrors.Errorf("unknown format: %v", format)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = writer.Write(results); err != nil {
|
if err = writer.Write(results); err != nil {
|
||||||
return xerrors.Errorf("failed to write results: %w", err)
|
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")
|
exitCode := c.Int("exit-code")
|
||||||
if exitCode != 0 {
|
if exitCode != 0 {
|
||||||
for _, result := range results {
|
for _, result := range results {
|
||||||
|
|||||||
@@ -41,7 +41,8 @@ func Scan(files extractor.FileMap) (string, string, []vulnerability.DetectedVuln
|
|||||||
case fos.RedHat, fos.CentOS:
|
case fos.RedHat, fos.CentOS:
|
||||||
s = redhat.NewScanner()
|
s = redhat.NewScanner()
|
||||||
default:
|
default:
|
||||||
return "", "", nil, xerrors.Errorf("unsupported os : %s", os.Family)
|
log.Logger.Warnf("unsupported os : %s", os.Family)
|
||||||
|
return "", "", nil, nil
|
||||||
}
|
}
|
||||||
pkgs, err := analyzer.GetPackages(files)
|
pkgs, err := analyzer.GetPackages(files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -48,8 +48,10 @@ func ScanImage(imageName, filePath string) (map[string][]vulnerability.DetectedV
|
|||||||
return nil, xerrors.Errorf("failed to scan image: %w", err)
|
return nil, xerrors.Errorf("failed to scan image: %w", err)
|
||||||
|
|
||||||
}
|
}
|
||||||
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
if osFamily != "" {
|
||||||
results[imageDetail] = osVulns
|
imageDetail := fmt.Sprintf("%s (%s %s)", target, osFamily, osVersion)
|
||||||
|
results[imageDetail] = osVulns
|
||||||
|
}
|
||||||
|
|
||||||
libVulns, err := library.Scan(files)
|
libVulns, err := library.Scan(files)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -89,17 +89,16 @@ func getDetail(vulnID string) (Severity, string, string, []string) {
|
|||||||
|
|
||||||
func getSeverity(details map[string]Vulnerability) Severity {
|
func getSeverity(details map[string]Vulnerability) Severity {
|
||||||
for _, source := range sources {
|
for _, source := range sources {
|
||||||
d, ok := details[source]
|
switch d, ok := details[source]; {
|
||||||
if !ok {
|
case !ok:
|
||||||
continue
|
continue
|
||||||
}
|
case d.CvssScore > 0:
|
||||||
if d.CvssScore > 0 {
|
|
||||||
return scoreToSeverity(d.CvssScore)
|
return scoreToSeverity(d.CvssScore)
|
||||||
} else if d.CvssScoreV3 > 0 {
|
case d.CvssScoreV3 > 0:
|
||||||
return scoreToSeverity(d.CvssScoreV3)
|
return scoreToSeverity(d.CvssScoreV3)
|
||||||
} else if d.Severity != 0 {
|
case d.Severity != 0:
|
||||||
return d.Severity
|
return d.Severity
|
||||||
} else if d.SeverityV3 != 0 {
|
case d.SeverityV3 != 0:
|
||||||
return d.SeverityV3
|
return d.SeverityV3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -151,14 +150,16 @@ func getReferences(details map[string]Vulnerability) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func scoreToSeverity(score float64) Severity {
|
func scoreToSeverity(score float64) Severity {
|
||||||
if score >= 9.0 {
|
switch {
|
||||||
|
case score >= 9.0:
|
||||||
return SeverityCritical
|
return SeverityCritical
|
||||||
} else if score >= 7.0 {
|
case score >= 7.0:
|
||||||
return SeverityHigh
|
return SeverityHigh
|
||||||
} else if score >= 4.0 {
|
case score >= 4.0:
|
||||||
return SeverityMedium
|
return SeverityMedium
|
||||||
} else if score > 0.0 {
|
case score > 0.0:
|
||||||
return SeverityLow
|
return SeverityLow
|
||||||
|
default:
|
||||||
|
return SeverityUnknown
|
||||||
}
|
}
|
||||||
return SeverityUnknown
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func Update() (err error) {
|
|||||||
return xerrors.Errorf("error in Alpine OVAL update: %w", err)
|
return xerrors.Errorf("error in Alpine OVAL update: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update RedHat
|
// Update RedHat
|
||||||
log.Logger.Info("Updating RedHat data...")
|
log.Logger.Info("Updating RedHat data...")
|
||||||
if err = redhat.Update(dir, updatedFiles); err != nil {
|
if err = redhat.Update(dir, updatedFiles); err != nil {
|
||||||
return xerrors.Errorf("error in RedHat update: %w", err)
|
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)
|
return xerrors.Errorf("error in Debian OVAL update: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Update Ubuntu
|
// Update Ubuntu
|
||||||
log.Logger.Info("Updating Ubuntu data...")
|
log.Logger.Info("Updating Ubuntu data...")
|
||||||
if err = ubuntu.Update(dir, updatedFiles); err != nil {
|
if err = ubuntu.Update(dir, updatedFiles); err != nil {
|
||||||
return xerrors.Errorf("error in Ubuntu update: %w", err)
|
return xerrors.Errorf("error in Ubuntu update: %w", err)
|
||||||
|
|||||||
Reference in New Issue
Block a user