Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Generate NeuVector vulnerability database
| **OS based** |
| Alpine | https://secdb.alpinelinux.org/ |
| Amazon | https://alas.aws.amazon.com/ |
| Chainguard | https://packages.cgr.dev/chainguard/security.json |
| Debian | https://security-tracker.debian.org/tracker/data/json |
| Microsoft mariner | https://github.com/microsoft/CBL-MarinerVulnerabilityData |
| Oracle OS | https://linux.oracle.com/oval/ |
Expand All @@ -18,6 +19,7 @@ Generate NeuVector vulnerability database
| Red Hat/CentOS | https://www.redhat.com/security/data/oval/v2/ |
| SUSE Linux | https://ftp.suse.com/pub/projects/security/oval/ |
| Ubuntu | https://launchpad.net/ubuntu-cve-tracker |
| Wolfi | https://packages.wolfi.dev/os/security.json |
| **Application based** |
| .NET | https://github.com/advisories, https://www.cvedetails.com/vulnerability-list/vendor_id-26/ |
| apache | https://www.cvedetails.com/vendor/45/Apache.html |
Expand Down
2 changes: 2 additions & 0 deletions dbgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
_ "github.com/vul-dbgen/updater/fetchers/alpine"
_ "github.com/vul-dbgen/updater/fetchers/amazon"
_ "github.com/vul-dbgen/updater/fetchers/apps"
_ "github.com/vul-dbgen/updater/fetchers/chainguard"
_ "github.com/vul-dbgen/updater/fetchers/debian"
_ "github.com/vul-dbgen/updater/fetchers/mariner"
_ "github.com/vul-dbgen/updater/fetchers/oracle"
Expand All @@ -25,6 +26,7 @@ import (
_ "github.com/vul-dbgen/updater/fetchers/rocky"
_ "github.com/vul-dbgen/updater/fetchers/suse"
_ "github.com/vul-dbgen/updater/fetchers/ubuntu"
_ "github.com/vul-dbgen/updater/fetchers/wolfi"
)

func usage() {
Expand Down
4 changes: 4 additions & 0 deletions memdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ const (
dbSuse
dbPhoton
dbRocky
dbWolfi
dbChainguard
dbMax
)

Expand Down Expand Up @@ -181,6 +183,8 @@ func (db *memDB) UpdateDb(version string) bool {
dbs.buffers[dbSuse] = dbBuffer{namespace: "sles", indexFile: "suse_index.tb", fullFile: "suse_full.tb"}
dbs.buffers[dbPhoton] = dbBuffer{namespace: "photon", indexFile: "photon_index.tb", fullFile: "photon_full.tb"}
dbs.buffers[dbRocky] = dbBuffer{namespace: "rocky", indexFile: "rocky_index.tb", fullFile: "rocky_full.tb"}
dbs.buffers[dbWolfi] = dbBuffer{namespace: "wolfi", indexFile: "wolfi_index.tb", fullFile: "wolfi_full.tb"}
dbs.buffers[dbChainguard] = dbBuffer{namespace: "chainguard", indexFile: "chainguard_index.tb", fullFile: "chainguard_full.tb"}

dbs.rawSHA = make([][sha256.Size]byte, len(db.rawFiles))

Expand Down
140 changes: 140 additions & 0 deletions updater/fetchers/chainguard/chainguard.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package chainguard

import (
"encoding/json"
"io/ioutil"
"net/http"
"regexp"
"strings"

log "github.com/sirupsen/logrus"

"github.com/vul-dbgen/common"
"github.com/vul-dbgen/updater"
)

const (
securityURL = "https://packages.cgr.dev/chainguard/security.json"
updaterFlag = "chainguard-secdbUpdater"
cveURLPrefix = "https://cve.mitre.org/cgi-bin/cvename.cgi?name="
// Chainguard uses rolling releases, so we use a generic version identifier
chainguardVersion = "rolling"
)

var cveRegex = regexp.MustCompile(`^CVE-\d{4}-\d{4,}$`)

type ChainguardFetcher struct{}

type secDBData struct {
APKUrl string `json:"apkurl"`
Archs []string `json:"archs"`
RepoName string `json:"reponame"`
URLPrefix string `json:"urlprefix"`
Packages []struct {
Pkg struct {
Name string `json:"name"`
SecFixes map[string]json.RawMessage `json:"secfixes"`
} `json:"pkg"`
} `json:"packages"`
}

func init() {
updater.RegisterFetcher("chainguard", &ChainguardFetcher{})
}

func parseSecDB(body []byte, url string) ([]common.Vulnerability, error) {
var data secDBData
if err := json.Unmarshal(body, &data); err != nil {
log.WithError(err).WithFields(log.Fields{"url": url}).Warn("Failed to unmarshal chainguard db")
return nil, err
}

var vulns []common.Vulnerability
for _, pkg := range data.Packages {
for version, raw := range pkg.Pkg.SecFixes {
// Skip version "0" entries as they represent false positives
if version == "0" {
continue
}

ver, err := common.NewVersion(version)
if err != nil {
log.WithError(err).WithField("version", version).Warn("Failed to parse package version. skipping")
continue
}

var cves []string
if err = json.Unmarshal(raw, &cves); err != nil {
continue
}

for _, cveName := range cves {
// Filter out GHSA identifiers, only process CVEs
if !cveRegex.MatchString(cveName) {
continue
}

if year, err := common.ParseYear(cveName[4:]); err != nil {
log.WithField("cve", cveName).Warn("Unable to parse year from CVE name")
continue
} else if year < common.FirstYear {
continue
}

if s := strings.Index(cveName, " "); s != -1 {
cveName = cveName[:s]
}

var vuln common.Vulnerability
vuln.Name = cveName
vuln.Link = cveURLPrefix + cveName

featureVersion := common.FeatureVersion{
Feature: common.Feature{
Namespace: "chainguard:" + chainguardVersion,
Name: pkg.Pkg.Name,
},
Version: ver,
}
vuln.FixedIn = append(vuln.FixedIn, featureVersion)

vulns = append(vulns, vuln)

common.DEBUG_VULN(&vuln, "chainguard")
}
}
}

return vulns, nil
}

func (u *ChainguardFetcher) downloadSecDB(url string) ([]common.Vulnerability, error) {
r, err := http.Get(url)
if err != nil {
log.WithError(err).WithFields(log.Fields{"url": url}).Error("Failed to download chainguard db")
return nil, err
}

body, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()

return parseSecDB(body, url)
}

func (u *ChainguardFetcher) FetchUpdate() (resp updater.FetcherResponse, err error) {
log.WithField("package", "Chainguard").Info("Start fetching vulnerabilities")

// Download security.json
if vulns, err := u.downloadSecDB(securityURL); err == nil {
resp.Vulnerabilities = append(resp.Vulnerabilities, vulns...)
} else {
return resp, err
}

log.WithFields(log.Fields{"Vulnerabilities": len(resp.Vulnerabilities)}).Info("fetching chainguard done")
return resp, nil
}

func (u *ChainguardFetcher) Clean() {
// No cleanup needed for Chainguard fetcher
}
140 changes: 140 additions & 0 deletions updater/fetchers/wolfi/wolfi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package wolfi

import (
"encoding/json"
"io/ioutil"
"net/http"
"regexp"
"strings"

log "github.com/sirupsen/logrus"

"github.com/vul-dbgen/common"
"github.com/vul-dbgen/updater"
)

const (
securityURL = "https://packages.wolfi.dev/os/security.json"
updaterFlag = "wolfi-secdbUpdater"
cveURLPrefix = "https://cve.mitre.org/cgi-bin/cvename.cgi?name="
// Wolfi uses rolling releases, so we use a generic version identifier
wolfiVersion = "rolling"
)

var cveRegex = regexp.MustCompile(`^CVE-\d{4}-\d{4,}$`)

type WolfiFetcher struct{}

type secDBData struct {
APKUrl string `json:"apkurl"`
Archs []string `json:"archs"`
RepoName string `json:"reponame"`
URLPrefix string `json:"urlprefix"`
Packages []struct {
Pkg struct {
Name string `json:"name"`
SecFixes map[string]json.RawMessage `json:"secfixes"`
} `json:"pkg"`
} `json:"packages"`
}

func init() {
updater.RegisterFetcher("wolfi", &WolfiFetcher{})
}

func parseSecDB(body []byte, url string) ([]common.Vulnerability, error) {
var data secDBData
if err := json.Unmarshal(body, &data); err != nil {
log.WithError(err).WithFields(log.Fields{"url": url}).Warn("Failed to unmarshal wolfi db")
return nil, err
}

var vulns []common.Vulnerability
for _, pkg := range data.Packages {
for version, raw := range pkg.Pkg.SecFixes {
// Skip version "0" entries as they represent false positives
if version == "0" {
continue
}

ver, err := common.NewVersion(version)
if err != nil {
log.WithError(err).WithField("version", version).Warn("Failed to parse package version. skipping")
continue
}

var cves []string
if err = json.Unmarshal(raw, &cves); err != nil {
continue
}

for _, cveName := range cves {
// Filter out GHSA identifiers, only process CVEs
if !cveRegex.MatchString(cveName) {
continue
}

if year, err := common.ParseYear(cveName[4:]); err != nil {
log.WithField("cve", cveName).Warn("Unable to parse year from CVE name")
continue
} else if year < common.FirstYear {
continue
}

if s := strings.Index(cveName, " "); s != -1 {
cveName = cveName[:s]
}

var vuln common.Vulnerability
vuln.Name = cveName
vuln.Link = cveURLPrefix + cveName

featureVersion := common.FeatureVersion{
Feature: common.Feature{
Namespace: "wolfi:" + wolfiVersion,
Name: pkg.Pkg.Name,
},
Version: ver,
}
vuln.FixedIn = append(vuln.FixedIn, featureVersion)

vulns = append(vulns, vuln)

common.DEBUG_VULN(&vuln, "wolfi")
}
}
}

return vulns, nil
}

func (u *WolfiFetcher) downloadSecDB(url string) ([]common.Vulnerability, error) {
r, err := http.Get(url)
if err != nil {
log.WithError(err).WithFields(log.Fields{"url": url}).Error("Failed to download wolfi db")
return nil, err
}

body, _ := ioutil.ReadAll(r.Body)
defer r.Body.Close()

return parseSecDB(body, url)
}

func (u *WolfiFetcher) FetchUpdate() (resp updater.FetcherResponse, err error) {
log.WithField("package", "Wolfi").Info("Start fetching vulnerabilities")

// Download security.json
if vulns, err := u.downloadSecDB(securityURL); err == nil {
resp.Vulnerabilities = append(resp.Vulnerabilities, vulns...)
} else {
return resp, err
}

log.WithFields(log.Fields{"Vulnerabilities": len(resp.Vulnerabilities)}).Info("fetching wolfi done")
return resp, nil
}

func (u *WolfiFetcher) Clean() {
// No cleanup needed for Wolfi fetcher
}