Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

False Positives Associated with Chainguard Images #1179

Closed
jspeed-meyers opened this issue Mar 14, 2023 · 5 comments
Closed

False Positives Associated with Chainguard Images #1179

jspeed-meyers opened this issue Mar 14, 2023 · 5 comments
Labels
bug Something isn't working changelog-ignore Don't include this issue in the release changelog false-positive

Comments

@jspeed-meyers
Copy link

What happened:

This is a list of false positives associated with using grype to scan Chainguard Images. The table below provides detailed information on each false positive, including the scanner version, database build date, and image. I have shortened the image digests to make the table readable for a GitHub issue. More context on the activities that led to this reporting of false positives can be found in this blog post. A public Google Sheets with the data below (and the full digests) can be found here. I should note that this data was collected largely in January 2023.

What you expected to happen:

I expected these false positives not to occur.

How to reproduce it:

image digest scanner scanner_version db_built_data day_of_scan package_name package_version package_type CVE
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 delegate 0.2.0 gem CVE-1999-1338
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 delegate 0.2.0 gem CVE-2005-0861
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 delegate 0.2.0 gem CVE-2005-0036
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 find 0.1.1 gem CVE-2020-24550
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef4 grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 logger 1.5.0 gem CVE-2017-14727
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 matrix 0.4.2 gem CVE-2017-14197
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 matrix 0.4.2 gem CVE-2017-14198
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 observer 0.1.1 gem CVE-2008-4318
cgr.dev/chainguard/ruby:latest-3.1 sha256:d9c4ef grype 0.53.0 2022-12-24 08:16:41 +0000 UTC 2022/12/24 readline 0.0.3 gem CVE-2014-2524
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 cgi 0.2.1 gem CVE-2021-41816
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 delegate 0.2.0 gem CVE-1999-1338
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 delegate 0.2.0 gem CVE-2005-0036
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 delegate 0.2.0 gem CVE-2005-0861
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 find 0.1.0 gem CVE-2020-24550
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 logger 1.4.3 gem CVE-2017-14727
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 matrix 0.3.1 gem CVE-2017-14197
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 matrix 0.3.1 gem CVE-2017-14198
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 observer 0.1.1 gem CVE-2008-4318
cgr.dev/chainguard/ruby:latest-3.0 sha256:5c3321 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 readline 0.0.2 gem CVE-2014-2524
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-resolver-api 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-resolver-connector-basic 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-resolver-impl 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-resolver-spi 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-resolver-transport-wagon 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-resolver-util 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-17 sha256:a361a2 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/9 maven-shared-utils 3.3.4 java-archive CVE-2021-26291
cgr.dev/chainguard/jenkins:latest sha256:6f6577 grype 0.55.0 2023-01-09 08:17:29 +0000 UTC 2023/1/10 commons-jelly-tags-fmt "1.0" java-archive CVE-2018-1000052
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-resolver-api 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-resolver-connector-basic 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-resolver-impl 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-resolver-spi 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-resolver-transport-wagon 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-resolver-util 1.6.3 java-archive CVE-2021-26291
cgr.dev/chainguard/maven:openjdk-11 sha256:e6fb94 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 maven-shared-utils 3.3.4 java-archive CVE-2021-26291
cgr.dev/chainguard/etcd:latest sha256:375a0c grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 google.golang.org/protobuf v1.27.1 go-module CVE-2015-5237
cgr.dev/chainguard/etcd:latest sha256:375a0c grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 google.golang.org/protobuf v1.27.1 go-module CVE-2021-22570
cgr.dev/chainguard/prometheus:latest sha256:7974e0 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 google.golang.org/protobuf v1.28.1 go-module CVE-2015-5237
cgr.dev/chainguard/prometheus:latest sha256:7974e0 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 google.golang.org/protobuf v1.28.1 go-module CVE-2021-22570
cgr.dev/chainguard/node:latest sha256:880e29 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 opener 1.5.2 npm CVE-2021-27478
cgr.dev/chainguard/node:latest sha256:880e29 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 opener 1.5.2 npm CVE-2021-27482
cgr.dev/chainguard/node:latest sha256:880e29 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 opener 1.5.2 npm CVE-2021-27498
cgr.dev/chainguard/node:latest sha256:880e29 grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 opener 1.5.2 npm CVE-2021-27500
cgr.dev/chainguard/kubectl:latest sha256:bbf8bf grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 google.golang.org/protobuf v1.28.0 go-module CVE-2015-5237
cgr.dev/chainguard/kubectl:latest sha256:bbf8bf grype 0.55.0 2023-01-11 08:19:24 +0000 UTC 2023/1/11 google.golang.org/protobuf v1.28.0 go-module CVE-2021-22570

Environment:

  • Output of grype version: See table above.
  • OS (e.g: cat /etc/os-release or similar): Apple M1 Pro, Ventura 13.2.1

cc @wagoodman @luhring

@alecxvs
Copy link

alecxvs commented Jul 14, 2023

Nice. I was just bitten by the CVEs affecting the C++ version of protobuf when I'm using the Go package. Arguably, it shouldn't even be included on those CVEs in Github because it's a completely different code base... if it were amended to remove the false Go listing, would that also clear up grype?

@jspeed-meyers
Copy link
Author

@alecxvs, sorry if you got bitten while using Chainguard Images. We definitely work to keep false positive scanner findings down on Chainguard Images but don't get all of them all of the time. This blog post mentions how we try to keep Chainguard Images (which play nice with Grype!) free of scanner findings, including one particular Go example recently.

But you're definitely in technical territory best covered by @wagoodman and @luhring here!

@alecxvs
Copy link

alecxvs commented Jul 14, 2023

Actually I was not using a chainguard image, I was consuming the New Relic infrastructure agent which has protobuf as a dependency. Anything using protobuf in Golang seems to be affected by this, then. But this issue seems to concisely cover the what and why regardless of which image is used.

@wagoodman
Copy link
Contributor

wagoodman commented Jul 29, 2024

Hey @jspeed-meyers ! A lot has changed in grype over the last year since this issue was opened, so I wanted to circle back and see how relevant these findings still are. An initial check that all of the findings you reported have been addressed ! 🎉 🌮

compare script

Note: you need to install grype and the legacy version of grype for this to function:

brew install grype # or any other flavor of install
curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- v0.55.0

As well as the spreadsheet in CSV form as data.csv locally

import csv
import subprocess
import os
import re
import json

def parse_csv(file_path):
    with open(file_path, newline='') as csvfile:
        reader = csv.DictReader(csvfile)
        return list(reader)

def run_syft(image, digest, output_dir):
    clean_image = re.sub('[^a-zA-Z0-9]', '_', image)
    sbom_file = os.path.join(output_dir, f"{clean_image}_{digest}.json")

    if not os.path.exists(sbom_file):
        command = f"syft {image}@{digest} -o json={sbom_file}"
        print("running command:", command)
        result = subprocess.run(command, shell=True, capture_output=True, text=True)

        if result.returncode != 0:
            print("Error:", result.stderr)
            exit(1)

    return sbom_file

def run_grype(binary_path, output_dir, sbom_file=None, image=None, digest=None):

    if image and not digest or digest and not image:
        raise ValueError("Both image and digest should be provided")

    if sbom_file:
        command = f"{binary_path} {sbom_file} -o json"
    else:
        command = f"{binary_path} {image}@{digest} -o json"

    clean_image = re.sub('[^a-zA-Z0-9]', '_', image)
    output_file = os.path.join(output_dir, f"{clean_image}_{digest}_{os.path.basename(binary_path)}.json")

    if os.path.exists(output_file):
        with open(output_file, 'r') as file:
            output = file.read()
    else:
        print("running command:", command)
        result = subprocess.run(command, shell=True, capture_output=True, text=True)

        if result.returncode != 0:
            print("Error:", result.stderr)
            exit(1)

        output = result.stdout

        with open(output_file, 'w') as file:
            file.write(output)

    return output_file

def check_cve_and_package(output_file, package_name, cve):
    with open(output_file, 'r') as file:
        grype_output = json.load(file)

    cve_present = False

    for match in grype_output.get("matches", []):
        vuln = match.get("vulnerability", {})
        artifact = match.get("artifact", {})

        if artifact.get("name").lower() == package_name:
            if vuln.get("id").lower() == cve:
                cve_present = True

    return cve_present

def check_package_in_syft(sbom_file, package_name):
    with open(sbom_file, 'r') as file:
        syft_output = json.load(file)

    for artifact in syft_output.get("artifacts", []):
        if artifact.get("name").lower() == package_name:
            return True
    return False

def main():
    csv_data = parse_csv('data.csv')
    old_binary_path = './bin/grype'
    new_binary_path = 'grype'
    output_sbom_dir = 'output/sbom'
    output_old_dir = 'output/old'
    output_new_dir = 'output/new'

    print("old grype version:\n" + subprocess.run(f"{old_binary_path} version", shell=True, capture_output=True, text=True).stdout)
    print("new grype version:\n" + subprocess.run(f"{new_binary_path} version", shell=True, capture_output=True, text=True).stdout)

    os.makedirs(output_sbom_dir, exist_ok=True)
    os.makedirs(output_old_dir, exist_ok=True)
    os.makedirs(output_new_dir, exist_ok=True)

    results = []

    fixed_count = 0
    reproduced_count = 0
    total_count = len(csv_data)
    for row in csv_data:
        image = row['image'].strip()
        digest = row['digest'].strip()
        package_name = row['package_name'].strip().lower()
        cve = row['CVE'].strip().lower()

        sbom_file = run_syft(image, digest, output_sbom_dir)

        bin_grype_output = run_grype(old_binary_path, output_old_dir, image=image, digest=digest) # run against image
        grype_output = run_grype(new_binary_path, output_new_dir, sbom_file=sbom_file, image=image, digest=digest) # run against sbom

        package_present_in_syft = check_package_in_syft(sbom_file, package_name)
        cve_present_bin = check_cve_and_package(bin_grype_output, package_name, cve)
        cve_present_grype = check_cve_and_package(grype_output, package_name, cve)

        if cve_present_bin:
            reproduced_count += 1

        fixed = not cve_present_grype

        if fixed:
            fixed_count += 1

        results.append({
            'image': image,
            'digest': digest,
            'package_name': package_name,
            'cve': cve,
            'package_present': 'yes' if package_present_in_syft else 'no',
            'reproduced': 'yes' if cve_present_bin else 'no',
            'fixed?': 'yes' if fixed else 'no'
        })

    markdown = "| Image | Package Name | CVE | Package Present | Reproduced | Fixed? |\n"
    markdown += "|-------|--------------|-----|-----------------|------------|--------|\n"
    for result in results:
        markdown += f"| {result['image']} | {result['package_name']} | {result['cve']} | {result['package_present']} | {result['reproduced']} | {result['fixed?']} |\n"

    print(markdown)

    print("Reproduced :", reproduced_count)
    print("Fixed      :", fixed_count)
    print("Total      :", total_count)


if __name__ == "__main__":
    main()
script output
old grype version:

Application:          grype
Version:              0.55.0
Syft Version:         v0.65.0
BuildDate:            2023-01-04T21:18:26Z
GitCommit:            c559833c7e02aed827773adb4f9677cb398577be
GitDescription:       v0.55.0
Platform:             darwin/arm64
GoVersion:            go1.18.9
Compiler:             gc
Supported DB Schema:  5

new grype version:

Application:         grype
Version:             0.79.3
BuildDate:           2024-07-11T18:39:52Z
GitCommit:           brew
GitDescription:      [not provided]
Platform:            darwin/arm64
GoVersion:           go1.22.5
Compiler:            gc
Syft Version:        v1.9.0
Supported DB Schema: 5
Image Package Name CVE Package Present Reproduced Fixed?
cgr.dev/chainguard/ruby:latest-3.1 delegate cve-1999-1338 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 delegate cve-2005-0861 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 delegate cve-2005-0036 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 find cve-2020-24550 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 logger cve-2017-14727 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 matrix cve-2017-14197 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 matrix cve-2017-14198 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 observer cve-2008-4318 yes yes yes
cgr.dev/chainguard/ruby:latest-3.1 readline cve-2014-2524 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 cgi cve-2021-41816 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 delegate cve-1999-1338 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 delegate cve-2005-0036 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 delegate cve-2005-0861 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 find cve-2020-24550 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 logger cve-2017-14727 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 matrix cve-2017-14197 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 matrix cve-2017-14198 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 observer cve-2008-4318 yes yes yes
cgr.dev/chainguard/ruby:latest-3.0 readline cve-2014-2524 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-resolver-api cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-resolver-connector-basic cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-resolver-impl cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-resolver-spi cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-resolver-transport-wagon cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-resolver-util cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-17 maven-shared-utils cve-2021-26291 yes yes yes
cgr.dev/chainguard/jenkins:latest commons-jelly-tags-fmt cve-2018-1000052 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-resolver-api cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-resolver-connector-basic cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-resolver-impl cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-resolver-spi cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-resolver-transport-wagon cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-resolver-util cve-2021-26291 yes yes yes
cgr.dev/chainguard/maven:openjdk-11 maven-shared-utils cve-2021-26291 yes yes yes
cgr.dev/chainguard/etcd:latest google.golang.org/protobuf cve-2015-5237 yes yes yes
cgr.dev/chainguard/etcd:latest google.golang.org/protobuf cve-2021-22570 yes yes yes
cgr.dev/chainguard/prometheus:latest google.golang.org/protobuf cve-2015-5237 yes yes yes
cgr.dev/chainguard/prometheus:latest google.golang.org/protobuf cve-2021-22570 yes yes yes
cgr.dev/chainguard/node:latest opener cve-2021-27478 yes yes yes
cgr.dev/chainguard/node:latest opener cve-2021-27482 yes yes yes
cgr.dev/chainguard/node:latest opener cve-2021-27498 yes yes yes
cgr.dev/chainguard/node:latest opener cve-2021-27500 yes yes yes
cgr.dev/chainguard/kubectl:latest google.golang.org/protobuf cve-2015-5237 yes yes yes
cgr.dev/chainguard/kubectl:latest google.golang.org/protobuf cve-2021-22570 yes yes yes
Reproduced : 44
Fixed      : 44
Total      : 44

Thank you @jspeed-meyers for the work on getting this data together + the detailed blog post!

Since there are no more FPs from this data set, I'll close this issue for now, but shout out if I'm missing anything here.

@github-project-automation github-project-automation bot moved this to Done in OSS Jul 29, 2024
@wagoodman wagoodman added the changelog-ignore Don't include this issue in the release changelog label Jul 29, 2024
@jspeed-meyers
Copy link
Author

@wagoodman --- OMG. This is my favorite GH issue ever now. Great work to the grype team. Holy cow! 🐮 I'm really impressed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working changelog-ignore Don't include this issue in the release changelog false-positive
Projects
Archived in project
Development

No branches or pull requests

3 participants